diff options
162 files changed, 5000 insertions, 734 deletions
diff --git a/WebContent/VAADIN/themes/base/upload/upload.scss b/WebContent/VAADIN/themes/base/upload/upload.scss index 933482764c..f8e707446c 100644 --- a/WebContent/VAADIN/themes/base/upload/upload.scss +++ b/WebContent/VAADIN/themes/base/upload/upload.scss @@ -4,11 +4,13 @@ white-space: nowrap; } - .#{$primaryStyleName}-immediate { position: relative; margin: 0; overflow: hidden; + .v-button { + width:100%; + } } .v-ff & .#{$primaryStyleName}-immediate, @@ -36,4 +38,4 @@ text-align: left; } -}
\ No newline at end of file +} diff --git a/WebContent/VAADIN/themes/valo/components/_accordion.scss b/WebContent/VAADIN/themes/valo/components/_accordion.scss index 91ce4efe33..40ab29f862 100644 --- a/WebContent/VAADIN/themes/valo/components/_accordion.scss +++ b/WebContent/VAADIN/themes/valo/components/_accordion.scss @@ -2,7 +2,7 @@ * Outputs the selectors and properties for the Accordion component. * * @param {string} $primary-stylename (v-accordion) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * @group accordion */ @mixin valo-accordion ($primary-stylename: v-accordion, $include-additional-styles: contains($v-included-additional-styles, accordion)) { diff --git a/WebContent/VAADIN/themes/valo/components/_button.scss b/WebContent/VAADIN/themes/valo/components/_button.scss index eb57e20d2a..b1b16f5bde 100644 --- a/WebContent/VAADIN/themes/valo/components/_button.scss +++ b/WebContent/VAADIN/themes/valo/components/_button.scss @@ -2,7 +2,7 @@ * Outputs the selectors and properties for the Button component. * * @param {string} $primary-stylename (v-button) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group button */ @@ -164,7 +164,7 @@ /** * Outputs the styles for a button variant. * - * @param {size} $unit-size ($v-unit-size) - The sizing of the button, which corresponds its height + * @param {size} $unit-size ($v-unit-size) - The sizing of the button, which corresponds its height * @param {size | list} $padding (null) - The padding of the button. Computed from other parameters by default. * @param {color} $font-color (null) - The font color of the button. Computed from the $background-color by default. * @param {number} $font-weight ($v-font-weight + 100) - The font weight of the button @@ -349,7 +349,7 @@ * Output styles for a borderless button. Expects that the targeted element * already has both valo-button-static-style and valo-button-style included. * - * @param {color} $font-color (inherit) - The font color of the borderless button + * @param {color} $font-color (inherit) - The font color of the borderless button * * @group button */ diff --git a/WebContent/VAADIN/themes/valo/components/_checkbox.scss b/WebContent/VAADIN/themes/valo/components/_checkbox.scss index 7ad08ad74d..3c418ec9b7 100644 --- a/WebContent/VAADIN/themes/valo/components/_checkbox.scss +++ b/WebContent/VAADIN/themes/valo/components/_checkbox.scss @@ -2,7 +2,7 @@ * Outputs the selectors and properties for the CheckBox component. * * @param {string} $primary-stylename (v-checkbox) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group checkbox */ @@ -43,8 +43,8 @@ * Outputs the styles for a checkbox variant. * * @param {color} $background-color ($v-background-color) - The background color of the checkbox - * @param {size} $unit-size ($v-unit-size) - The sizing of the checkbox. The width and height of the checkbox will be the unit-size divided by 2. - * @param {color} $selection-color ($v-selection-color) - The color of the checked state icon + * @param {size} $unit-size ($v-unit-size) - The sizing of the checkbox. The width and height of the checkbox will be the unit-size divided by 2. + * @param {color} $selection-color ($v-selection-color) - The color of the checked state icon * * @group checkbox */ diff --git a/WebContent/VAADIN/themes/valo/components/_combobox.scss b/WebContent/VAADIN/themes/valo/components/_combobox.scss index 79107eb0d1..f84faef603 100644 --- a/WebContent/VAADIN/themes/valo/components/_combobox.scss +++ b/WebContent/VAADIN/themes/valo/components/_combobox.scss @@ -2,7 +2,7 @@ * Outputs the selectors and properties for the ComboBox component. * * @param {string} $primary-stylename (v-filterselect) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group combobox */ @@ -93,7 +93,7 @@ /** * Outputs the styles for a combobox variant. * - * @param {size} $unit-size ($v-unit-size) - The sizing of the combobox, which corresponds its height + * @param {size} $unit-size ($v-unit-size) - The sizing of the combobox, which corresponds its height * @param {color} $font-color (null) - The font color of the combobox. Computed from the $background-color by default. * @param {number} $font-weight (max(400, $v-font-weight)) - The font weight of the combobox * @param {size} $font-size (null) - The font size of the combobox. Inherited from the parent by default. @@ -201,7 +201,7 @@ /** * Outputs the styles for a combobox variant input element. * - * @param {size} $unit-size ($v-unit-size) - The sizing of the input (affects the padding only, width and height are 100%) + * @param {size} $unit-size ($v-unit-size) - The sizing of the input (affects the padding only, width and height are 100%) * @param {size | list} $padding (null) - The padding of the input. Computed from other parameters by default. * @param {color} $font-color (null) - The font color of the input. Computed from the $background-color by default. * @param {number} $font-weight (null) - The font weight of the input. Inherited from the parent by default. @@ -257,7 +257,7 @@ /** * Outputs the styles for a combobox variant button element. * - * @param {size} $unit-size ($v-unit-size) - The sizing of the button, which corresponds its width. + * @param {size} $unit-size ($v-unit-size) - The sizing of the button, which corresponds its width. * @param {list} $bevel ($v-textfield-bevel) - Box-shadow value according to $v-bevel documentation * @param {color} $background-color ($v-textfield-background-color) - The background color of the input, which affects the font color of the button * @param {size} $border-radius ($v-textfield-border-radius) - The border-radius of the input, which affects the border-radius of the button diff --git a/WebContent/VAADIN/themes/valo/components/_csslayout.scss b/WebContent/VAADIN/themes/valo/components/_csslayout.scss index 3525bcad5a..c06d3c2441 100644 --- a/WebContent/VAADIN/themes/valo/components/_csslayout.scss +++ b/WebContent/VAADIN/themes/valo/components/_csslayout.scss @@ -11,7 +11,7 @@ $v-component-group-spacing: null !default; * Outputs the additional styles for the CssLayout component. Does not produce any other output. * * @param {string} $primary-stylename (v-csslayout) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group csslayout */ diff --git a/WebContent/VAADIN/themes/valo/components/_datefield.scss b/WebContent/VAADIN/themes/valo/components/_datefield.scss index 71b50b5a77..3201288120 100644 --- a/WebContent/VAADIN/themes/valo/components/_datefield.scss +++ b/WebContent/VAADIN/themes/valo/components/_datefield.scss @@ -2,7 +2,7 @@ * Outputs the selectors and properties for the DateField component. * * @param {string} $primary-stylename (v-datefield) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group datefield */ @@ -120,7 +120,7 @@ * * @param {list} $bevel ($v-textfield-bevel) - Box-shadow value according to $v-bevel documentation * @param {list} $shadow ($v-textfield-shadow) - Box-shadow value according to $v-shadow documentation - * @param {size} $unit-size ($v-unit-size) - The sizing of the datefield, which corresponds its height + * @param {size} $unit-size ($v-unit-size) - The sizing of the datefield, which corresponds its height * @param {list} $border ($v-textfield-border) - The border of the datefield * @param {size} $border-radius ($v-textfield-border-radius) - The border-radius of the datefield * @param {color} $background-color ($v-textfield-background-color) - The background color of the datefield @@ -189,7 +189,7 @@ /** * Outputs the styles for a date field variant button element. * - * @param {size} $unit-size ($v-unit-size) - The sizing of the button, which corresponds its width. + * @param {size} $unit-size ($v-unit-size) - The sizing of the button, which corresponds its width. * @param {list} $bevel ($v-textfield-bevel) - Box-shadow value according to $v-bevel documentation * @param {color} $background-color ($v-textfield-background-color) - The background color of the input, which affects the font color of the button * @param {size} $border-radius ($v-textfield-border-radius) - The border-radius of the input, which affects the border-radius of the button diff --git a/WebContent/VAADIN/themes/valo/components/_formlayout.scss b/WebContent/VAADIN/themes/valo/components/_formlayout.scss index da3d0b987f..35627ebd79 100644 --- a/WebContent/VAADIN/themes/valo/components/_formlayout.scss +++ b/WebContent/VAADIN/themes/valo/components/_formlayout.scss @@ -2,7 +2,7 @@ * Outputs the selectors and properties for the FormLayout component. * * @param {string} $primary-stylename (v-formlayout) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group formlayout */ @@ -51,6 +51,8 @@ > .v-label-h4 { position: absolute; left: 0; + right: 0; + width: auto !important; margin-top: -0.5em; padding-bottom: 0.5em; border-bottom: valo-border($color: $v-app-background-color, $strength: 0.5); @@ -85,17 +87,17 @@ $right: $margin; $bottom: $margin; $left: $margin; - } @else if length($margin) == 2 { + } @else if length($margin) == 2 { $top: nth($margin, 1); $right: nth($margin, 2); $bottom: nth($margin, 1); $left: nth($margin, 2); - } @else if length($margin) == 3 { + } @else if length($margin) == 3 { $top: nth($margin, 1); $right: nth($margin, 2); $bottom: nth($margin, 3); $left: nth($margin, 2); - } @else if length($margin) == 4 { + } @else if length($margin) == 4 { $top: nth($margin, 1); $right: nth($margin, 2); $bottom: nth($margin, 3); @@ -114,8 +116,22 @@ padding-left: $left; } + [class*="margin-left"] > tbody > [class*="row"] > [class*="contentcell"] { + > .v-label-h2, + > .v-label-h3, + > .v-label-h4 { + left: $left; + } + } + [class*="margin-right"] > tbody > [class*="row"] > [class*="contentcell"] { padding-right: $right; + + > .v-label-h2, + > .v-label-h3, + > .v-label-h4 { + right: $right; + } } } @@ -141,7 +157,7 @@ /** * Outputs the styles for a light style form layout. This mixin expects the target to have the normal styles of a form layout applied. * - * @param {size} $row-height ($v-unit-size) - The height of an individual form layout row + * @param {size} $row-height ($v-unit-size) - The height of an individual form layout row * * @group formlayout */ @@ -150,7 +166,7 @@ padding: 0; } - > table > tbody > [class*="row"] > td { + > table > tbody > tr > td { padding-top: 0; height: $row-height; // Effectively min-height border-bottom: valo-border($color: $v-app-background-color, $strength: 0.3); @@ -160,7 +176,7 @@ border-bottom: none; } - > table > tbody > [class*="row"] > [class*="captioncell"] { + > table > tbody > tr > [class*="captioncell"] { color: valo-font-color($v-background-color, .5); text-align: right; padding-left: ceil($v-unit-size/3); @@ -168,6 +184,8 @@ } > table > tbody > [class*="row"] > [class*="contentcell"] { + padding-right: 0; + > .v-textfield, > .v-textarea, > .v-filterselect, @@ -208,6 +226,8 @@ > .v-label-h3, > .v-label-h4 { border-bottom: none; + left: 0; + right: 0; } > .v-label-h3, diff --git a/WebContent/VAADIN/themes/valo/components/_label.scss b/WebContent/VAADIN/themes/valo/components/_label.scss index b59d3e0e21..cfec847271 100644 --- a/WebContent/VAADIN/themes/valo/components/_label.scss +++ b/WebContent/VAADIN/themes/valo/components/_label.scss @@ -101,7 +101,7 @@ $v-letter-spacing--h4: 0 !default; * Outputs the selectors and styles for the Label component. * * @param {string} $primary-stylename (v-label) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group label */ diff --git a/WebContent/VAADIN/themes/valo/components/_table.scss b/WebContent/VAADIN/themes/valo/components/_table.scss index d8a673294d..a70532ccfd 100644 --- a/WebContent/VAADIN/themes/valo/components/_table.scss +++ b/WebContent/VAADIN/themes/valo/components/_table.scss @@ -612,7 +612,7 @@ $v-table-background-color: null !default; * @group table */ @mixin valo-table-sort-asc-icon-style { - content: '\f0dd'; + content: '\f0de'; font-family: FontAwesome; } @@ -623,7 +623,7 @@ $v-table-background-color: null !default; * @group table */ @mixin valo-table-sort-desc-icon-style { - content: '\f0de'; + content: '\f0dd'; font-family: FontAwesome; } diff --git a/WebContent/VAADIN/themes/valo/components/_tabsheet.scss b/WebContent/VAADIN/themes/valo/components/_tabsheet.scss index 7dafbe4624..bb3e55042a 100644 --- a/WebContent/VAADIN/themes/valo/components/_tabsheet.scss +++ b/WebContent/VAADIN/themes/valo/components/_tabsheet.scss @@ -63,7 +63,7 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; * Outputs the selectors and properties for the TabSheet component. * * @param {string} $primary-stylename (v-tabsheet) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group tabsheet */ @@ -208,6 +208,7 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; overflow: hidden; text-overflow: ellipsis; border-bottom: max(1px, first-number($v-border))*2 solid transparent; + position: relative; @if $v-animations-enabled { @include transition(border-bottom 200ms, color 200ms); @@ -229,7 +230,6 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; @include opacity($v-disabled-opacity); cursor: default; color: inherit !important; - border-bottom: none; } } @@ -251,14 +251,23 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; color: $v-selection-color; } + .v-caption-closable { + padding-right: round($v-unit-size/10) + round($v-font-size * 1.1); + } + + &.icons-on-top .v-caption-closable { + padding-right: round($v-unit-size/10); + } + .#{$primary-stylename}-caption-close { - display: inline-block; + position: absolute; + right: 0; + top: 50%; + margin: round($v-font-size / -2) 0 0; font-size: round($v-font-size * 1.1); line-height: round($v-font-size * 1.1); width: round($v-font-size * 1.1); - vertical-align: middle; text-align: center; - margin: 0 round($v-font-size/-4) 0 round($v-font-size/2); border-radius: round($v-border-radius/2); color: valo-font-color($v-app-background-color, 0.4); @@ -388,7 +397,7 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; /** * Outputs the styles for the framed tabsheet style. * - * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors + * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors * @param {bool} $frame-inactive-tabs (true) - Should inactive tabs be framed as well (the active tab is always framed with this style) * @param {bool} $outer-frame (true) - Should the frame contain the whole tabsheet (i.e. tabbar and tab content). If false, works like a "borderless" style. * @param {size} $tab-spacing ($v-unit-size/10) - The spacing between tabs @@ -398,9 +407,9 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; @mixin valo-tabsheet-framed-style ($primary-stylename: v-tabsheet, $frame-inactive-tabs: true, $outer-frame: true, $tab-spacing: round($v-unit-size/10)) { > .#{$primary-stylename}-tabcontainer { .v-caption { - position: relative; margin-left: $tab-spacing or first-number($v-border) * -1; padding: 0 $v-layout-spacing-horizontal; + background-color: $v-app-background-color; border: first-number($v-border) solid transparent; line-height: $v-unit-size - first-number($v-border); border-radius: $v-border-radius $v-border-radius 0 0; @@ -414,6 +423,20 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; background-color: darken($v-app-background-color, 3%); border-bottom-color: first-color(valo-border($color: $v-app-background-color, $strength: 0.5)); } + + &.v-disabled:hover { + background-color: $v-app-background-color; + } + } + + .v-caption-closable { + padding-right: $v-layout-spacing-horizontal + round($v-font-size * 1.1); + } + + .#{$primary-stylename}-caption-close { + top: round($v-font-size/4); + right: round($v-font-size/4); + margin-top: 0; } td:first-child .v-caption, @@ -433,17 +456,6 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; border-bottom: none; padding-bottom: first-number($v-border); } - - .v-caption-closable { - padding-right: $v-layout-spacing-horizontal + round($v-font-size * 1.1); - } - - .#{$primary-stylename}-caption-close { - position: absolute; - top: round($v-font-size/4); - right: round($v-font-size/4); - margin: 0; - } } > .#{$primary-stylename}-content { @@ -471,8 +483,10 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; } } - &.icons-on-top .v-caption-closable { - padding-right: $v-layout-spacing-horizontal; + &.icons-on-top { + > .#{$primary-stylename}-tabcontainer .#{$primary-stylename}-tabitem-selected .v-caption { + padding-bottom: round($v-unit-size/6) + first-number($v-border); + } } } @@ -480,8 +494,8 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; /** * Outputs the styles for a tabsheet where the tabs are aligned to the position specified by the parameter in the tabbar. * - * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors - * @param {string} $align (center) - The alignment of the tabs inside the tabbar. Possible values: left, right, center. + * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors + * @param {string} $align (center) - The alignment of the tabs inside the tabbar. Possible values: left, right, center. * * @group tabsheet */ @@ -495,7 +509,7 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; /** * Outputs the styles for a tabsheet where all tabs in the tabbar have equal width and span the entire width of the tabbar. * - * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors + * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors * @param {bool} $flex (false) - Should the size of the tabs be proportional to their content, i.e. should the available space in the tabbar be distributed to the tabs in relation to their content sizes. * * @group tabsheet @@ -530,22 +544,18 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; /** * Outputs the styles for a tabsheet where the icons of individual tabs are on top of the tab captions. * - * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors + * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors * * @group tabsheet */ @mixin valo-tabsheet-icons-on-top-style ($primary-stylename: v-tabsheet) { - > div > .#{$primary-stylename}-tabs { + > .#{$primary-stylename}-tabcontainer { .v-caption { padding-top: round($v-unit-size/6); padding-bottom: round($v-unit-size/6); line-height: 1.2; } - .#{$primary-stylename}-tabitem-selected .v-caption { - padding-bottom: round($v-unit-size/6) + first-number($v-border); - } - .v-icon { display: block; @@ -553,6 +563,15 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; margin-left: 0; } } + + .v-caption-closable { + padding-right: $v-layout-spacing-horizontal; + } + + .#{$primary-stylename}-caption-close { + top: round($v-font-size/4); + margin-top: 0; + } } } @@ -561,7 +580,7 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; * Outputs the styles for a tabsheet where only the selected tab has the close button visible. * Note that the other tabs can still be closed programmatically. * - * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors + * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors * * @group tabsheet */ @@ -580,7 +599,7 @@ $v-tabsheet-content-animation-enabled: $v-animations-enabled !default; * Outputs the styles for a tabsheet where the tabbar has increased padding to separate the tabs * inside it from their surrounding container. * - * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors + * @param {string} $primary-stylename (v-tabsheet) - The primary style name for the selectors * * @group tabsheet */ diff --git a/WebContent/VAADIN/themes/valo/components/_textarea.scss b/WebContent/VAADIN/themes/valo/components/_textarea.scss index ffd5ba855a..d600bc14c2 100644 --- a/WebContent/VAADIN/themes/valo/components/_textarea.scss +++ b/WebContent/VAADIN/themes/valo/components/_textarea.scss @@ -2,7 +2,7 @@ * Outputs the selectors and properties for the TextArea component. * * @param {string} $primary-stylename (v-textarea) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group textarea */ @@ -62,7 +62,7 @@ /** * Outputs the styles for a text area variant. * - * @param {size} $unit-size ($v-unit-size) - The sizing of the text area, which corresponds its height + * @param {size} $unit-size ($v-unit-size) - The sizing of the text area, which corresponds its height * @param {size | list} $padding (null) - The padding of the text area. Computed from other parameters by default. * @param {color} $font-color (null) - The font color of the text area. Computed from the $background-color by default. * @param {number} $font-weight (max(400, $v-font-weight)) - The font weight of the text area diff --git a/WebContent/VAADIN/themes/valo/components/_textfield.scss b/WebContent/VAADIN/themes/valo/components/_textfield.scss index f4ca3538bd..58f69e5e4c 100644 --- a/WebContent/VAADIN/themes/valo/components/_textfield.scss +++ b/WebContent/VAADIN/themes/valo/components/_textfield.scss @@ -51,7 +51,7 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default; * Outputs the selectors and properties for the TextField component. * * @param {string} $primary-stylename (v-textfield) - the primary style name for the selectors - * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component + * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component * * @group textfield */ @@ -122,7 +122,7 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default; /** * Outputs the styles for a text field variant. * - * @param {size} $unit-size ($v-unit-size) - The sizing of the text field, which corresponds its height + * @param {size} $unit-size ($v-unit-size) - The sizing of the text field, which corresponds its height * @param {size | list} $padding (null) - The padding of the text field. Computed from other parameters by default. * @param {color} $font-color (null) - The font color of the text field. Computed from the $background-color by default. * @param {number} $font-weight (max(400, $v-font-weight)) - The font weight of the text field @@ -254,7 +254,7 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default; * @param {list} $bevel ($v-textfield-bevel) - Box-shadow value according to $v-bevel documentation * @param {list} $shadow ($v-textfield-shadow) - Box-shadow value according to $v-shadow documentation * @param {color} $background-color ($v-textfield-background-color) - The background color of the text field - * @param {list} $gradient (null) - Valo specific gradient value. See the documentation for $v-gradient. + * @param {list} $gradient (null) - Valo specific gradient value. See the documentation for $v-gradient. * * @group textfield */ @@ -341,7 +341,7 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default; * @param {string | list} $stylenames (inline-icon) - The additional style names which will define the inline-icon style * @param {string} $input-selector (null) - Additional selector for a nested input element which should be targeted * @param {size} $unit-size ($v-unit-size) - The unit size which the resulting style will support - * @param {size} $font-size ($v-font-size) - The font size which the resulting style will support (needed for font icons) + * @param {size} $font-size ($v-font-size) - The font size which the resulting style will support (needed for font icons) * @param {size} $image-icon-size (16px) - The image icon height which the resulting style will support (needed to center the icon vertically inside the text field) * * @group text field diff --git a/WebContent/VAADIN/themes/valo/components/_treetable.scss b/WebContent/VAADIN/themes/valo/components/_treetable.scss index e025df2bc9..60b696315b 100644 --- a/WebContent/VAADIN/themes/valo/components/_treetable.scss +++ b/WebContent/VAADIN/themes/valo/components/_treetable.scss @@ -14,6 +14,12 @@ padding-left: 0; padding-right: 0; } + + [class*="caption-container"], + [class*="footer-container"] { + $vertical-padding: round(($v-table-row-height - $v-table-header-font-size)/2); + min-height: $v-table-row-height - $vertical-padding - ($vertical-padding - $v-table-border-width); + } [class*="cell-wrapper"] { min-height: $v-font-size; diff --git a/WebContent/VAADIN/themes/valo/components/_upload.scss b/WebContent/VAADIN/themes/valo/components/_upload.scss index c301be060a..07a51f03ef 100644 --- a/WebContent/VAADIN/themes/valo/components/_upload.scss +++ b/WebContent/VAADIN/themes/valo/components/_upload.scss @@ -1,7 +1,7 @@ /** * * - * @param {string} $primary-stylename (v-upload) - + * @param {string} $primary-stylename (v-upload) - * * @group upload */ @@ -10,6 +10,10 @@ @include valo-widget-style; } + .#{$primary-stylename}-immediate .v-button { + width: 100%; + } + .#{$primary-stylename}-immediate input[type="file"] { @include opacity(0); z-index: 2; @@ -20,4 +24,4 @@ border: none; background: transparent; } -}
\ No newline at end of file +} diff --git a/WebContent/VAADIN/themes/valo/util/_bevel-and-shadow.scss b/WebContent/VAADIN/themes/valo/util/_bevel-and-shadow.scss index 346a50c9de..1065161bfc 100644 --- a/WebContent/VAADIN/themes/valo/util/_bevel-and-shadow.scss +++ b/WebContent/VAADIN/themes/valo/util/_bevel-and-shadow.scss @@ -3,7 +3,7 @@ * * @group style * - * @param {list} $border ($v-border) - CSS border value which can contain any of the color keywords + * @param {list} $border ($v-border) - CSS border value which can contain any of the color keywords * @param {color} $color ($v-background-color) - the base color to which the color keywords are applied to * @param {color} $context (null) - context/surrounding color where the border is expected to appear. The color of the final border is the darker of the two parameters passed to this function. * @param {number} $strength (1) - adjustment for the border contrast @@ -59,7 +59,7 @@ * * @group style * - * @param {list} $border ($v-border) - CSS border value which can contain any of the color keywords + * @param {list} $border ($v-border) - CSS border value which can contain any of the color keywords * @param {color} $color ($v-background-color) - the base color to which the color keywords are applied to * @param {color} $context (null) - context/surrounding color where the border is expected to appear. The color of the final border is the darker of the two parameters passed to this function. * @param {number} $strength (1) - adjustment for the border contrast @@ -88,8 +88,8 @@ * @param {number} $bevel-depth ($v-bevel-depth) - percentage defining the depth/amount of the bevel effect. Affects the color keywords specified in the $bevel parameter. * @param {list} $shadow (null) - box-shadow value according to $v-shadow documentation * @param {number} $shadow-opacity ($v-shadow-opacity) - percentage defining the opacity/amount of the shadow effect. Affects the color keywords specified in the $shadow parameter. - * @param {color} $background-color ($v-background-color) - the base color to which the color keywords are applied to - * @param {list} $gradient (null) - Valo specific gradient value. See the documentation for $v-gradient. Affects the color keywords specified in the $bevel parameter. + * @param {color} $background-color ($v-background-color) - the base color to which the color keywords are applied to + * @param {list} $gradient (null) - Valo specific gradient value. See the documentation for $v-gradient. Affects the color keywords specified in the $bevel parameter. * @param {bool} $include-focus (false) - should the box-shadow value include $v-focus-style as well (only added if $v-focus-style is a) * * @return {list} CSS box-shadow value, combined from $bevel and $shadow with all occurences of v-tint, v-shade and v-tone color keywords replaced with the corresponding actual color @@ -160,7 +160,7 @@ * * @param {list} $list - any CSS list with possible color keywords * @param {color} $color - The color to which color keywords are applied to - * @param {list} $gradient (null) - Valo specific gradient value. See the documentation for $v-gradient. Affects the replacement colors to accommodate the gradient. + * @param {list} $gradient (null) - Valo specific gradient value. See the documentation for $v-gradient. Affects the replacement colors to accommodate the gradient. * * @return {list} The input $list parameter with all occurences of v-tint, v-shade and v-tone color keywords replaced with the corresponding actual color */ diff --git a/WebContent/VAADIN/themes/valo/util/_gradient.scss b/WebContent/VAADIN/themes/valo/util/_gradient.scss index 99490046ba..a38dca704c 100644 --- a/WebContent/VAADIN/themes/valo/util/_gradient.scss +++ b/WebContent/VAADIN/themes/valo/util/_gradient.scss @@ -5,7 +5,7 @@ * * @param {color} $color ($v-background-color) - The base color for the gradient color stops * @param {list} $gradient ($v-gradient) - Valo-specific gradient value. See the documentation for $v-gradient. - * @param {color} $fallback (null) - A fallback color for browser which do not support linear gradients (IE8 and IE9 in particular). If null, the base $color is used instead. + * @param {color} $fallback (null) - A fallback color for browser which do not support linear gradients (IE8 and IE9 in particular). If null, the base $color is used instead. * @param {string} $direction (to bottom) - the direction of the linear gradient. The color stops are by default so that a lighter shade is at the start and a darker shade is at the end. */ @mixin valo-gradient($color: $v-background-color, $gradient: $v-gradient, $fallback: null, $direction: to bottom) { diff --git a/WebContent/VAADIN/themes/valo/util/_lists.scss b/WebContent/VAADIN/themes/valo/util/_lists.scss index f82c4f0fe3..e21c69fd01 100644 --- a/WebContent/VAADIN/themes/valo/util/_lists.scss +++ b/WebContent/VAADIN/themes/valo/util/_lists.scss @@ -5,7 +5,7 @@ * @param {value} $var - the value to search for * @param {bool} $recursive (false) - should any contained lists be checked for the value * - * @return {bool} true if the value is found from the list, false otherwise + * @return {bool} true if the value is found from the list, false otherwise * * @group lists */ @@ -34,7 +34,7 @@ * * @param {list} $list - the list to check * - * @return {bool} true of the list contains other nested lists, false otherwise + * @return {bool} true of the list contains other nested lists, false otherwise * * @group lists */ @@ -132,7 +132,7 @@ /** * Flatten nested lists to one list, while maintaining the original list separators. * - * @param {list} $list - the list to flatten + * @param {list} $list - the list to flatten * * @return {list} the same list with all nested lists flattened * diff --git a/WebContent/VAADIN/themes/valo/util/_util.scss b/WebContent/VAADIN/themes/valo/util/_util.scss index 585504600d..510506805f 100644 --- a/WebContent/VAADIN/themes/valo/util/_util.scss +++ b/WebContent/VAADIN/themes/valo/util/_util.scss @@ -3,7 +3,7 @@ * * @param {string} $to-align (()) - The selector to match the elements which you wish to align vertically. The targeted elements should be inline or inline-block elements. * @param {string} $align (middle) - The vertical-align value, e.g. top, middle, bottom - * @param {string} $pseudo-element (after) - Which pseudo element to use for the vertical align guide + * @param {string} $pseudo-element (after) - Which pseudo element to use for the vertical align guide * * @group util */ diff --git a/WebContent/license.html b/WebContent/license.html index 0ce22da99c..48be15b98d 100644 --- a/WebContent/license.html +++ b/WebContent/license.html @@ -90,6 +90,16 @@ <td><a href="licenses/apache-license-version-2-0.txt">Apache License, Version 2.0</a></td> </tr> + <tr> + <td>Closure Stylesheets</td> + <td><a href="licenses/apache-license-version-2-0.txt">Apache License, Version 2.0</a></td> + </tr> + + <tr> + <td>ASM</td> + <td><a href="licenses/ow2-asm-license.txt">ASM Project License</a></td> + </tr> + <!-- In vaadin-shared-deps --> <tr> <td>Guava</td> @@ -99,7 +109,7 @@ <!-- In vaadin-shared-deps --> <tr> <td>JSON</td> - <td><a href="licenses/the-json-license.txt">The JSON License</a></td> + <td><a href="licenses/apache-license-version-2-0.txt">Apache License, Version 2.0</a></td> </tr> <!-- Used by vaadin-server --> diff --git a/WebContent/licenses/ow2-asm-license.txt b/WebContent/licenses/ow2-asm-license.txt new file mode 100644 index 0000000000..b8ed869a5c --- /dev/null +++ b/WebContent/licenses/ow2-asm-license.txt @@ -0,0 +1,31 @@ +http://asm.ow2.org/license.html + +Copyright (c) 2000-2011 INRIA, France Telecom +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html index 8ba85cfac1..c22f0e5ed4 100644 --- a/WebContent/release-notes.html +++ b/WebContent/release-notes.html @@ -497,12 +497,12 @@ </p> <ul> - <li>Mozilla Firefox 18-29</li> - <li>Mozilla Firefox 17 ESR, 24 ESR</li> + <li>Mozilla Firefox 18-33</li> + <li>Mozilla Firefox 17 ESR, 24 ESR, 31 ESR</li> <li>Internet Explorer 8-11</li> - <li>Safari 6-7</li> - <li>Opera 12, 16-20</li> - <li>Google Chrome 23-34</li> + <li>Safari 6-8</li> + <li>Opera 12, 16-25</li> + <li>Google Chrome 23-38</li> </ul> <p> @@ -511,7 +511,7 @@ </p> <ul> - <li>iOS 5-7</li> + <li>iOS 5-8</li> <li>Android 2.3-4</li> <li>Windows Phone 8</li> </ul> diff --git a/build.properties b/build.properties index a9ad640e53..9df1c8d767 100644 --- a/build.properties +++ b/build.properties @@ -6,5 +6,5 @@ vaadin.url=http://vaadin.com vaadin.java.version=1.6 vaadin.version=0.0.0.unversioned-development-build vaadin.sass.version=0.9.10 -gwt.version=2.6.0.vaadin5 +gwt.version=2.7.0.beta1vaadin1 commons-io.version=2.4 diff --git a/build/ide.xml b/build/ide.xml index fff4ba911d..7c5267ef30 100755 --- a/build/ide.xml +++ b/build/ide.xml @@ -29,10 +29,10 @@ <path refid="client-compiler.deps" /> <path refid="server.deps" /> <path refid="shared.deps" /> - <path refid="uitest.deps" /> <path refid="client.deps" /> <path refid="buildhelpers.deps" /> <path refid="gwt.deps" /> + <path refid="uitest.deps" /> <path location="server/src" /> <path location="shared/src" /> <path location="uitest/src" /> @@ -163,6 +163,7 @@ <sysproperty key="vFailIfNotSerializable" value="true" /> <jvmarg value="-Xss8M" /> + <jvmarg value="-Xmx1G" /> <jvmarg value="-XX:MaxPermSize=256M" /> <jvmarg value="-Djava.awt.headless=true" /> <jvmarg value="-Dgwt.usearchives=false" /> diff --git a/client-compiler/ivy.xml b/client-compiler/ivy.xml index 0b87069f2c..af60b76e22 100644 --- a/client-compiler/ivy.xml +++ b/client-compiler/ivy.xml @@ -44,6 +44,12 @@ conf="build,ide -> default" /> <dependency org="ant" name="ant-launcher" rev="1.6.5" conf="build,ide -> default" /> + <dependency org="org.ow2.asm" name="asm" + rev="5.0.3" conf="build-> default" /> + <dependency org="org.ow2.asm" name="asm-util" + rev="5.0.3" conf="build-> default" /> + <dependency org="org.ow2.asm" name="asm-commons" + rev="5.0.3" conf="build-> default" /> <dependency org="org.eclipse.jetty" name="jetty-annotations" rev="8.1.12.v20130726" conf="build,ide -> default"> @@ -88,7 +94,7 @@ conf="build,ide -> default" /> <dependency org="com.vaadin" name="vaadin-client-compiler-deps" - rev="1.1.0" conf="build,ide -> default" /> + rev="1.2.0" conf="build,ide -> default" /> </dependencies> diff --git a/client-compiler/src/com/vaadin/tools/CvalChecker.java b/client-compiler/src/com/vaadin/tools/CvalChecker.java index 53cbce798e..b3345c7658 100644 --- a/client-compiler/src/com/vaadin/tools/CvalChecker.java +++ b/client-compiler/src/com/vaadin/tools/CvalChecker.java @@ -32,10 +32,11 @@ import java.util.Locale; import java.util.ResourceBundle; import java.util.prefs.Preferences; +import org.apache.commons.io.IOUtils; + import elemental.json.JsonException; import elemental.json.JsonObject; import elemental.json.impl.JsonUtil; -import org.apache.commons.io.IOUtils; /** * This class is able to validate the vaadin CVAL license. @@ -54,8 +55,8 @@ public final class CvalChecker { * It is not in a separate f le, so as it is easier to copy into any product * which does not depend on vaadin core. * - * We are using org.json in order not to use additional dependency like - * auto-beans, gson, etc. + * We are using elemental.json in order not to use additional dependency + * like auto-beans, gson, etc. */ public static class CvalInfo { diff --git a/client/src/com/vaadin/Vaadin.gwt.xml b/client/src/com/vaadin/Vaadin.gwt.xml index aad0563975..5e8f08fe22 100644 --- a/client/src/com/vaadin/Vaadin.gwt.xml +++ b/client/src/com/vaadin/Vaadin.gwt.xml @@ -13,11 +13,7 @@ <inherits name="com.google.gwt.json.JSON" /> <inherits name="com.google.gwt.logging.Logging" /> - <!-- Firebug handler is deprecated but for some reason still enabled - by default --> - <set-property name="gwt.logging.firebugHandler" value="DISABLED" /> - <!-- Disable popup logging as we have our own popup logger --> - <set-property name="gwt.logging.popupHandler" value="DISABLED" /> + <set-property name="gwt.logging.enabled" value="TRUE" /> <inherits name="com.vaadin.VaadinBrowserSpecificOverrides" /> @@ -58,10 +54,9 @@ <!-- Use the new cross site linker to get a nocache.js without document.write --> <add-linker name="xsiframe" /> - <extend-property name="user.agent" values="opera" /> <!-- Remove IE6/IE7 permutation as they are not supported --> - <set-property name="user.agent" value="ie8,ie9,ie10,gecko1_8,safari,opera" /> + <set-property name="user.agent" value="ie8,ie9,ie10,gecko1_8,safari" /> <!-- Pointer event support --> <define-property name="modernie" values="none,yes" /> diff --git a/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml b/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml index 45ede928f5..ceedde50a6 100644 --- a/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml +++ b/client/src/com/vaadin/VaadinBrowserSpecificOverrides.gwt.xml @@ -44,14 +44,4 @@ </any> </replace-with> - <replace-with class="com.vaadin.client.ui.VPopupImpl"> - <when-type-is - class="com.google.gwt.user.client.ui.impl.PopupImplMozilla" /> - <when-property-is name="user.agent" value="gecko1_8" /> - </replace-with> - - <replace-with class="com.vaadin.client.ui.VPopupImpl"> - <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl" /> - </replace-with> - </module> diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java index 83dd90b6c2..12b1585292 100644 --- a/client/src/com/vaadin/client/ApplicationConfiguration.java +++ b/client/src/com/vaadin/client/ApplicationConfiguration.java @@ -32,6 +32,8 @@ import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.client.RunAsyncCallback; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.core.client.ScriptInjector; +import com.google.gwt.dom.client.Element; import com.google.gwt.logging.client.LogConfiguration; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Window; @@ -598,11 +600,20 @@ public class ApplicationConfiguration implements EntryPoint { } } + private boolean vaadinBootstrapLoaded() { + Element window = ScriptInjector.TOP_WINDOW.cast(); + return window.getPropertyJSO("vaadin") != null; + } + @Override public void onModuleLoad() { - // Don't run twice if the module has been inherited several times. - if (moduleLoaded) { + // Don't run twice if the module has been inherited several times, + // and don't continue if vaadinBootstrap was not executed. + if (moduleLoaded || !vaadinBootstrapLoaded()) { + getLogger() + .log(Level.WARNING, + "vaadinBootstrap.js was not loaded, skipping vaadin application configuration."); return; } moduleLoaded = true; diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java index d61af537a9..edd1273bf5 100644 --- a/client/src/com/vaadin/client/VTooltip.java +++ b/client/src/com/vaadin/client/VTooltip.java @@ -132,6 +132,22 @@ public class VTooltip extends VOverlay { } if (info.getTitle() != null && !info.getTitle().isEmpty()) { description.setInnerHTML(info.getTitle()); + /* + * Issue #11871: to correctly update the offsetWidth of description + * element we need to clear style width of it's parent DIV from old + * value (in some strange cases this width=[tooltip MAX_WIDTH] after + * tooltip text has been already updated to new shortly value: + * + * <div class="popupContent"> <div style="width: 500px;"> <div + * class="v-errormessage" aria-hidden="true" style="display: none;"> + * <div class="gwt-HTML"> </div> </div> <div + * class="v-tooltip-text">This is a short tooltip</div> </div> + * + * and it leads to error during calculation offsetWidth (it is + * native GWT method getSubPixelOffsetWidth()) of description + * element") + */ + description.getParentElement().getStyle().clearWidth(); description.getStyle().clearDisplay(); } else { description.setInnerHTML(""); @@ -151,6 +167,7 @@ public class VTooltip extends VOverlay { // in the right or bottom edge. For this reason the tooltip is moved // first to 0,0 position so that the calculation goes correctly. setPopupPosition(0, 0); + setPopupPositionAndShow(new PositionCallback() { @Override public void setPosition(int offsetWidth, int offsetHeight) { diff --git a/client/src/com/vaadin/client/componentlocator/LocatorUtil.java b/client/src/com/vaadin/client/componentlocator/LocatorUtil.java index 1d1c06587b..7de0de3855 100644 --- a/client/src/com/vaadin/client/componentlocator/LocatorUtil.java +++ b/client/src/com/vaadin/client/componentlocator/LocatorUtil.java @@ -15,6 +15,8 @@ */ package com.vaadin.client.componentlocator; +import com.google.gwt.regexp.shared.RegExp; + /** * Common String manipulator utilities used in VaadinFinderLocatorStrategy and * SelectorPredicates. @@ -73,4 +75,31 @@ public class LocatorUtil { protected static int indexOfIgnoringQuoted(String str, char find) { return indexOfIgnoringQuoted(str, find, 0); } + + /** + * Checks if path refers to vaadin UI element com.vaadin.ui.UI. + * + * @param path + * to vaadin element + * @return true if path refers to UI element, false otherwise + */ + public static boolean isUIElement(String path) { + String regex = "^\\/{0,2}(com\\.vaadin\\.ui\\.)?V?UI[\\/\\[]?"; + RegExp regexp = RegExp.compile(regex); + return regexp.test(path); + } + + /** + * Checks if path refers to vaadin Notification element + * com.vaadin.ui.Notification. + * + * @param path + * to vaadin element + * @return true if path refers to Notification element, false otherwise + */ + public static boolean isNotificationElement(String path) { + String regex = "^\\/{0,2}(com\\.vaadin\\.ui\\.)?V?Notification[\\/\\[]?"; + RegExp regexp = RegExp.compile(regex); + return regexp.test(path); + } } diff --git a/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java b/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java index a36ea1ac85..44bdeddff3 100644 --- a/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java +++ b/client/src/com/vaadin/client/componentlocator/VaadinFinderLocatorStrategy.java @@ -17,6 +17,7 @@ package com.vaadin.client.componentlocator; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.List; import com.google.gwt.dom.client.Document; @@ -267,32 +268,6 @@ public class VaadinFinderLocatorStrategy implements LocatorStrategy { return connectorHierarchy; } - private boolean isNotificationExpression(String path) { - String[] starts = { "//", "/" }; - - String[] frags = { "com.vaadin.ui.Notification.class", - "com.vaadin.ui.Notification", "VNotification.class", - "VNotification", "Notification.class", "Notification" }; - - String[] ends = { "/", "[" }; - - for (String s : starts) { - for (String f : frags) { - if (path.equals(s + f)) { - return true; - } - - for (String e : ends) { - if (path.startsWith(s + f + e)) { - return true; - } - } - } - } - - return false; - } - /** * {@inheritDoc} */ @@ -305,7 +280,7 @@ public class VaadinFinderLocatorStrategy implements LocatorStrategy { } List<Element> elements = new ArrayList<Element>(); - if (isNotificationExpression(path)) { + if (LocatorUtil.isNotificationElement(path)) { for (VNotification n : findNotificationsByPath(path)) { elements.add(n.getElement()); @@ -579,11 +554,19 @@ public class VaadinFinderLocatorStrategy implements LocatorStrategy { ComponentConnector parent, String pathFragment, boolean collectRecursively) { ArrayList<ComponentConnector> potentialMatches = new ArrayList<ComponentConnector>(); + String widgetName = getWidgetName(pathFragment); + // Special case when searching for UIElement. + if (LocatorUtil.isUIElement(pathFragment)) { + if (connectorMatchesPathFragment(parent, widgetName)) { + potentialMatches.add(parent); + } + } if (parent instanceof HasComponentsConnector) { + List<ComponentConnector> children = ((HasComponentsConnector) parent) .getChildComponents(); for (ComponentConnector child : children) { - String widgetName = getWidgetName(pathFragment); + if (connectorMatchesPathFragment(child, widgetName)) { potentialMatches.add(child); } @@ -744,19 +727,9 @@ public class VaadinFinderLocatorStrategy implements LocatorStrategy { */ private final <T> List<T> eliminateDuplicates(List<T> list) { - int l = list.size(); - for (int j = 0; j < l; ++j) { - T ref = list.get(j); - - for (int i = j + 1; i < l; ++i) { - if (list.get(i) == ref) { - list.remove(i); - --i; - --l; - } - } - } - + LinkedHashSet<T> set = new LinkedHashSet<T>(list); + list.clear(); + list.addAll(set); return list; } diff --git a/client/src/com/vaadin/client/debug/internal/theme/font.eot b/client/src/com/vaadin/client/debug/internal/theme/font.eot Binary files differindex c2a63b3f08..cf38942e0a 100644..100755 --- a/client/src/com/vaadin/client/debug/internal/theme/font.eot +++ b/client/src/com/vaadin/client/debug/internal/theme/font.eot diff --git a/client/src/com/vaadin/client/debug/internal/theme/font.svg b/client/src/com/vaadin/client/debug/internal/theme/font.svg index 9d00e7b2fc..c5a97a6c8b 100644..100755 --- a/client/src/com/vaadin/client/debug/internal/theme/font.svg +++ b/client/src/com/vaadin/client/debug/internal/theme/font.svg @@ -3,34 +3,34 @@ <svg xmlns="http://www.w3.org/2000/svg"> <metadata>Generated by IcoMoon</metadata> <defs> -<font id="icomoon" horiz-adv-x="512"> -<font-face units-per-em="512" ascent="480" descent="-32" /> -<missing-glyph horiz-adv-x="512" /> -<glyph unicode=" " d="" horiz-adv-x="256" /> -<glyph unicode="" d="M381.186 86.878l-19.971 158.833c-5.863 46.622-48.723 84.419-95.716 84.419h-14.532c-47.001 0-89.858-37.817-95.716-84.419l-19.97-158.833c-1.436-11.424 6.727-20.682 18.243-20.682h209.425c11.51 0 19.677 9.259 18.24 20.682zM258.649 282.012c-0.247-0.002-0.88-0.024-1.846-0.089-1.701-0.113-3.619-0.303-5.697-0.592-5.904-0.816-11.787-2.227-17.148-4.329-4.881-1.913-9.060-4.299-12.364-7.148-2.764-2.384-5.232-5.065-7.418-7.995-3.359-4.502-5.904-9.371-7.723-14.231-0.628-1.681-1.117-3.22-1.477-4.573-0.119-0.443-0.212-0.821-0.316-1.281-1.186-6.304-7.257-10.453-13.564-9.268-6.304 1.186-10.453 7.257-9.268 13.564 0.127 0.667 0.355 1.684 0.705 2.995 0.548 2.050 1.262 4.301 2.161 6.703 2.546 6.805 6.097 13.6 10.862 19.983 3.173 4.252 6.786 8.176 10.868 11.697 5.449 4.699 11.878 8.372 19.062 11.185 7.233 2.832 14.846 4.657 22.436 5.708 2.645 0.366 5.115 0.613 7.35 0.759 1.398 0.092 2.451 0.131 3.103 0.139 6.414 0.075 11.675-5.065 11.752-11.479 0.077-6.412-5.062-11.675-11.476-11.75zM240.26 405.353c0-9.469 7.678-17.147 17.147-17.147s17.147 7.678 17.147 17.147v55.31c0 9.469-7.678 17.147-17.147 17.147s-17.147-7.678-17.147-17.147v-55.31zM382.291 357.86c-8.071-4.954-10.599-15.509-5.649-23.581s15.509-10.6 23.581-5.649l47.144 28.922c8.071 4.953 10.599 15.509 5.649 23.581-4.954 8.071-15.509 10.6-23.581 5.649l-47.144-28.921zM109.74 327.524c8.071-4.953 18.629-2.422 23.581 5.649 4.953 8.071 2.422 18.63-5.649 23.581l-47.144 28.921c-8.071 4.954-18.63 2.422-23.581-5.649-4.953-8.071-2.422-18.63 5.649-23.581l47.145-28.921zM146.053 49.625c-11.511 0-20.84-9.339-20.84-20.836v-30.617c0-11.507 9.314-20.836 20.84-20.836h222.163c11.51 0 20.841 9.339 20.841 20.836v30.617c0 11.507-9.313 20.836-20.841 20.836h-222.163z" horiz-adv-x="536" /> -<glyph unicode="" d="M329.143 242.286q0 52.857-37.572 90.428t-90.428 37.572-90.428-37.572-37.572-90.428 37.572-90.428 90.428-37.572 90.428 37.572 37.572 90.428zM475.428 4.572q0-14.857-10.857-25.714t-25.714-10.857q-15.428 0-25.714 10.857l-98 97.714q-51.143-35.428-114-35.428-40.857 0-78.143 15.857t-64.285 42.857-42.857 64.286-15.857 78.143 15.857 78.143 42.857 64.286 64.285 42.857 78.143 15.857 78.143-15.857 64.286-42.857 42.857-64.286 15.857-78.143q0-62.857-35.428-114l98-98q10.572-10.572 10.572-25.714z" horiz-adv-x="476" /> -<glyph unicode="" d="M477.428 318.286q0-11.428-8-19.428l-245.714-245.714q-8-8-19.428-8t-19.428 8l-142.286 142.286q-8 8-8 19.428t8 19.428l38.857 38.857q8 8 19.428 8t19.428-8l84-84.286 187.429 187.714q8 8 19.428 8t19.428-8l38.857-38.857q8-8 8-19.429z" /> -<glyph unicode="" d="M370.857 102.286q0-11.428-8-19.428l-38.857-38.857q-8-8-19.428-8t-19.428 8l-84 84-84-84q-8-8-19.428-8t-19.428 8l-38.857 38.857q-8 8-8 19.428t8 19.428l84 84-84 84q-8 8-8 19.428t8 19.428l38.857 38.857q8 8 19.428 8t19.428-8l84-84 84 84q8 8 19.428 8t19.428-8l38.857-38.857q8-8 8-19.428t-8-19.428l-84-84 84-84q8-8 8-19.428z" horiz-adv-x="403" /> -<glyph unicode="" d="M438.857 224q0-44.572-17.428-85.143t-46.857-70-70-46.857-85.143-17.428-85.143 17.428-70 46.857-46.857 70-17.428 85.143q0 52 23 98t64.715 77.143q12.285 9.143 27.285 7.143t23.857-14.286q9.143-12 7-27t-14.143-24.143q-28-21.143-43.285-51.714t-15.285-65.143q0-29.715 11.572-56.715t31.285-46.714 46.715-31.286 56.714-11.572 56.714 11.572 46.714 31.286 31.286 46.714 11.572 56.714q0 34.572-15.286 65.143t-43.286 51.714q-12 9.143-14.143 24.143t7 27q8.857 12.286 24 14.286t27.143-7.143q41.714-31.143 64.714-77.143t23-98zM256 443.428v-182.857q0-14.857-10.857-25.714t-25.715-10.857-25.714 10.857-10.857 25.714v182.857q0 14.857 10.857 25.715t25.714 10.857 25.714-10.857 10.857-25.715z" horiz-adv-x="439" /> -<glyph unicode="" d="M292.572 224q0 30.286-21.428 51.714t-51.714 21.428-51.714-21.428-21.428-51.714 21.428-51.714 51.714-21.428 51.714 21.428 21.428 51.714zM438.857 255.143v-63.429q0-3.428-2.286-6.572t-5.714-3.714l-52.857-8q-5.428-15.428-11.143-26 10-14.286 30.572-39.428 2.857-3.428 2.857-7.143t-2.572-6.572q-7.714-10.572-28.286-30.857t-26.857-20.286q-3.428 0-7.428 2.572l-39.428 30.857q-12.572-6.572-26-10.857-4.572-38.857-8.286-53.143-2-8-10.286-8h-63.428q-4 0-7 2.428t-3.286 6.143l-8 52.572q-14 4.572-25.714 10.572l-40.285-30.572q-2.857-2.572-7.143-2.572-4 0-7.143 3.143-36 32.572-47.143 48-2 2.857-2 6.572 0 3.428 2.285 6.572 4.285 6 14.572 19t15.428 20.143q-7.715 14.286-11.715 28.286l-52.285 7.714q-3.715 0.572-6 3.572t-2.285 6.714v63.428q0 3.429 2.285 6.572t5.428 3.714l53.143 8q4 13.143 11.143 26.286-11.428 16.286-30.572 39.428-2.857 3.429-2.857 6.857 0 2.857 2.572 6.571 7.428 10.286 28.143 30.714t27 20.429q3.715 0 7.428-2.857l39.428-30.572q12.572 6.572 26 10.857 4.572 38.857 8.286 53.143 2 8 10.286 8h63.428q4 0 7-2.428t3.286-6.143l8-52.572q14-4.572 25.714-10.572l40.572 30.572q2.572 2.572 6.857 2.572 3.714 0 7.143-2.857 36.857-34 47.143-48.572 2-2.285 2-6.285 0-3.429-2.286-6.572-4.286-6-14.572-19t-15.428-20.143q7.428-14.285 11.714-28l52.286-8q3.714-0.571 6-3.571t2.286-6.714z" horiz-adv-x="439" /> -<glyph unicode="" d="M146.286 269.714v-164.571q0-4-2.571-6.572t-6.571-2.572h-18.285q-4 0-6.572 2.572t-2.572 6.572v164.572q0 4 2.572 6.571t6.572 2.571h18.285q4 0 6.572-2.571t2.571-6.572zM219.429 269.714v-164.571q0-4-2.571-6.572t-6.572-2.572h-18.286q-4 0-6.572 2.572t-2.571 6.572v164.572q0 4 2.571 6.571t6.572 2.571h18.286q4 0 6.572-2.571t2.571-6.572zM292.572 269.714v-164.571q0-4-2.572-6.572t-6.572-2.572h-18.286q-4 0-6.572 2.572t-2.571 6.572v164.572q0 4 2.571 6.571t6.572 2.571h18.286q4 0 6.572-2.571t2.572-6.572zM329.143 62.857v270.857h-256v-270.857q0-6.286 2-11.572t4.143-7.714 3-2.428h237.715q0.857 0 3 2.428t4.143 7.714 2 11.572zM137.143 370.286h128l-13.714 33.428q-2 2.572-4.857 3.143h-90.571q-2.857-0.571-4.857-3.143zM402.286 361.143v-18.286q0-4-2.572-6.572t-6.572-2.571h-27.428v-270.857q0-23.714-13.428-41t-32.286-17.286h-237.714q-18.857 0-32.285 16.714t-13.428 40.428v272h-27.428q-4 0-6.572 2.572t-2.571 6.571v18.286q0 4 2.571 6.572t6.572 2.571h88.285l20 47.714q4.285 10.572 15.429 18t22.572 7.429h91.428q11.428 0 22.572-7.429t15.428-18l20-47.714h88.286q4 0 6.572-2.571t2.572-6.572z" horiz-adv-x="403" /> -<glyph unicode="" d="M310.857 214.857v-18.286q0-3.714-2.714-6.428t-6.428-2.714h-109.714q-3.714 0-6.428 2.714t-2.714 6.428v128q0 3.714 2.714 6.428t6.428 2.714h18.286q3.714 0 6.428-2.714t2.714-6.428v-100.572h82.286q3.714 0 6.428-2.714t2.714-6.428zM365.714 224q0 29.714-11.572 56.714t-31.286 46.714-46.714 31.286-56.714 11.571-56.714-11.571-46.715-31.286-31.285-46.714-11.572-56.714 11.572-56.714 31.285-46.714 46.715-31.286 56.714-11.572 56.714 11.572 46.714 31.286 31.286 46.714 11.572 56.714zM438.857 224q0-59.714-29.428-110.143t-79.857-79.857-110.143-29.428-110.143 29.428-79.857 79.857-29.428 110.143 29.428 110.143 79.857 79.857 110.143 29.428 110.143-29.428 79.857-79.857 29.428-110.143z" horiz-adv-x="439" /> -<glyph unicode="" d="M431.714 178.286q0-1.428-0.286-2-18.286-76.572-76.572-124.143t-136.571-47.572q-41.715 0-80.715 15.714t-69.572 44.857l-36.857-36.857q-5.428-5.428-12.857-5.428t-12.857 5.428-5.428 12.857v128q0 7.428 5.428 12.857t12.857 5.428h128q7.428 0 12.857-5.428t5.429-12.857-5.428-12.857l-39.143-39.143q20.285-18.857 46-29.143t53.429-10.286q38.286 0 71.428 18.572t53.143 51.143q3.143 4.857 15.143 33.428 2.286 6.572 8.572 6.572h54.857q3.714 0 6.428-2.714t2.714-6.428zM438.857 406.857v-128q0-7.428-5.428-12.857t-12.857-5.428h-128q-7.428 0-12.857 5.428t-5.428 12.857 5.428 12.857l39.428 39.428q-42.286 39.143-99.714 39.143-38.286 0-71.428-18.571t-53.143-51.143q-3.143-4.857-15.143-33.429-2.285-6.572-8.572-6.572h-56.857q-3.715 0-6.428 2.714t-2.715 6.428v2q18.572 76.572 77.143 124.143t137.143 47.571q41.714 0 81.143-15.857t70-44.714l37.143 36.857q5.428 5.428 12.857 5.428t12.857-5.428 5.428-12.857z" horiz-adv-x="439" /> -<glyph unicode="" d="M201.143 187.428q0 15.143-10.714 25.857t-25.857 10.714-25.857-10.714-10.714-25.857q0-10.572 5.429-19.143t14.572-13.428l-19.714-65.428q-1.428-4.286 1.429-8t7.429-3.714h54.857q4.571 0 7.429 3.714t1.429 8l-19.715 65.428q9.143 4.857 14.572 13.428t5.428 19.143zM91.428 260.572h146.286v54.857q0 30.286-21.428 51.714t-51.714 21.429-51.715-21.429-21.428-51.714v-54.857zM329.143 233.143v-164.571q0-11.428-8-19.428t-19.428-8h-274.286q-11.428 0-19.428 8t-8 19.428v164.571q0 11.429 8 19.429t19.428 8h9.143v54.857q0 52.572 37.715 90.286t90.285 37.714 90.285-37.714 37.714-90.286v-54.857h9.143q11.428 0 19.428-8t8-19.428z" horiz-adv-x="329" /> -<glyph unicode="" d="M332.572 443.428q6.572 0 12.572-2.572 9.428-3.714 15-11.714t5.572-17.714v-368.286q0-9.714-5.572-17.714t-15-11.714q-5.428-2.286-12.572-2.286-13.714 0-23.714 9.143l-126 121.143-126-121.143q-10.285-9.428-23.715-9.428-6.572 0-12.572 2.572-9.428 3.714-15 11.714t-5.572 17.714v368.286q0 9.714 5.572 17.714t15 11.715q6 2.571 12.572 2.571h299.428z" horiz-adv-x="366" /> -<glyph unicode="" d="M292.572 86.857v18.286q0 4-2.572 6.572t-6.572 2.572h-27.428v137.143q0 4-2.571 6.571t-6.571 2.571h-91.428q-4 0-6.572-2.571t-2.571-6.572v-18.286q0-4 2.571-6.572t6.572-2.571h27.428v-109.715h-27.428q-4 0-6.572-2.572t-2.571-6.572v-18.286q0-4 2.571-6.572t6.572-2.572h128q4 0 6.572 2.572t2.572 6.572zM256 306.286v54.857q0 4-2.571 6.571t-6.571 2.572h-54.857q-4 0-6.571-2.572t-2.571-6.571v-54.857q0-4 2.571-6.572t6.572-2.571h54.857q4 0 6.571 2.571t2.572 6.572zM438.857 224q0-59.714-29.428-110.143t-79.857-79.857-110.143-29.428-110.143 29.428-79.857 79.857-29.428 110.143 29.428 110.143 79.857 79.857 110.143 29.428 110.143-29.428 79.857-79.857 29.428-110.143z" horiz-adv-x="439" /> -<glyph unicode="" d="M342 187.428h-31.143q-7.428 0-12.857 5.428t-5.428 12.857v36.572q0 7.428 5.428 12.857t12.857 5.429h31.143q-9.143 30.857-32.143 53.857t-53.857 32.143v-31.143q0-7.429-5.429-12.857t-12.857-5.428h-36.571q-7.428 0-12.857 5.428t-5.429 12.857v31.143q-30.857-9.143-53.857-32.143t-32.143-53.857h31.143q7.429 0 12.857-5.428t5.428-12.857v-36.571q0-7.428-5.428-12.857t-12.857-5.428h-31.143q9.143-30.857 32.143-53.857t53.857-32.143v31.143q0 7.428 5.428 12.857t12.857 5.428h36.571q7.428 0 12.857-5.428t5.429-12.857v-31.143q30.857 9.143 53.857 32.143t32.143 53.857zM438.857 242.286v-36.572q0-7.428-5.428-12.857t-12.857-5.428h-40.857q-10.572-46-44.143-79.572t-79.572-44.143v-40.857q0-7.428-5.428-12.857t-12.857-5.428h-36.571q-7.428 0-12.857 5.428t-5.429 12.857v40.857q-46 10.572-79.572 44.143t-44.143 79.572h-40.857q-7.428 0-12.857 5.428t-5.428 12.857v36.572q0 7.428 5.428 12.857t12.857 5.429h40.857q10.572 46 44.143 79.572t79.572 44.143v40.857q0 7.428 5.428 12.857t12.857 5.428h36.571q7.428 0 12.857-5.428t5.429-12.857v-40.857q46-10.571 79.572-44.143t44.143-79.572h40.857q7.428 0 12.857-5.428t5.428-12.857z" horiz-adv-x="439" /> -<glyph unicode="" d="M365.714 224q0 39.714-20.286 74.286l-200.286-200.286q34.572-20.286 74.286-20.286 29.714 0 56.714 11.572t46.714 31.286 31.286 46.714 11.572 56.714zM93.428 149.714l200.286 200.286q-34.572 20.286-74.286 20.286-29.714 0-56.714-11.572t-46.715-31.286-31.285-46.714-11.572-56.714q0-39.714 20.285-74.286zM438.857 224q0-59.714-29.428-110.143t-79.857-79.857-110.143-29.428-110.143 29.428-79.857 79.857-29.428 110.143 29.428 110.143 79.857 79.857 110.143 29.428 110.143-29.428 79.857-79.857 29.428-110.143z" horiz-adv-x="439" /> -<glyph unicode="" d="M215.714 178.286q0-3.714-2.857-6.572l-94.857-94.857 41.143-41.143q5.429-5.428 5.429-12.857t-5.428-12.857-12.857-5.428h-128q-7.428 0-12.857 5.428t-5.428 12.857v128q0 7.428 5.428 12.857t12.857 5.428 12.857-5.428l41.143-41.143 94.857 94.857q2.857 2.857 6.572 2.857t6.572-2.857l32.572-32.572q2.857-2.857 2.857-6.572zM438.857 425.143v-128q0-7.429-5.428-12.857t-12.857-5.428-12.857 5.428l-41.143 41.143-94.857-94.857q-2.857-2.857-6.572-2.857t-6.572 2.857l-32.572 32.572q-2.857 2.857-2.857 6.572t2.857 6.572l94.857 94.857-41.143 41.143q-5.428 5.428-5.428 12.857t5.428 12.857 12.857 5.428h128q7.428 0 12.857-5.428t5.428-12.857z" horiz-adv-x="439" /> -<glyph unicode="" d="M219.429 205.714v-128q0-7.428-5.429-12.857t-12.857-5.428-12.857 5.428l-41.143 41.143-94.857-94.857q-2.857-2.857-6.572-2.857t-6.572 2.857l-32.572 32.572q-2.857 2.857-2.857 6.572t2.857 6.572l94.857 94.857-41.143 41.143q-5.428 5.428-5.428 12.857t5.428 12.857 12.857 5.428h128q7.428 0 12.857-5.428t5.429-12.857zM435.143 397.714q0-3.714-2.857-6.571l-94.857-94.857 41.143-41.143q5.428-5.429 5.428-12.857t-5.428-12.857-12.857-5.429h-128q-7.428 0-12.857 5.428t-5.429 12.857v128q0 7.429 5.428 12.857t12.857 5.428 12.857-5.428l41.143-41.143 94.857 94.857q2.857 2.857 6.572 2.857t6.572-2.857l32.572-32.572q2.857-2.857 2.857-6.572z" horiz-adv-x="439" /> -<glyph unicode="" d="M219.429 443.428q59.715 0 110.143-29.428t79.857-79.857 29.428-110.143-29.428-110.143-79.857-79.857-110.143-29.428-110.143 29.428-79.857 79.857-29.428 110.143 29.428 110.143 79.857 79.857 110.143 29.428zM256 87.143v54.286q0 4-2.571 6.714t-6.286 2.714h-54.857q-3.714 0-6.572-2.857t-2.857-6.572v-54.286q0-3.714 2.857-6.572t6.572-2.857h54.857q3.714 0 6.286 2.714t2.571 6.714zM255.429 185.428l5.143 177.428q0 3.429-2.857 5.143-2.857 2.286-6.857 2.286h-62.857q-4 0-6.857-2.286-2.857-1.714-2.857-5.143l4.857-177.428q0-2.857 2.857-5t6.857-2.143h52.857q4 0 6.714 2.143t3 5z" horiz-adv-x="439" /> -<glyph unicode="" d="M292.572 87.143v54.286q0 4-2.714 6.714t-6.428 2.714h-54.857q-3.714 0-6.429-2.714t-2.714-6.714v-54.286q0-4 2.714-6.714t6.428-2.714h54.857q3.714 0 6.428 2.714t2.714 6.714zM292 194l5.143 131.143q0 3.428-2.857 5.428-3.714 3.143-6.857 3.143h-62.857q-3.143 0-6.857-3.143-2.857-2-2.857-6l4.857-130.572q0-2.857 2.857-4.714t6.857-1.857h52.857q4 0 6.714 1.857t3 4.714zM288 460.857l219.428-402.285q10-18-0.572-36-4.857-8.286-13.286-13.143t-18.143-4.857h-438.857q-9.715 0-18.143 4.857t-13.286 13.143q-10.572 18-0.572 36l219.429 402.286q4.857 8.857 13.429 14t18.572 5.143 18.572-5.143 13.428-14z" /> -<glyph unicode="" d="M438.857 96v-36.572q0-7.428-5.428-12.857t-12.857-5.428h-402.286q-7.428 0-12.857 5.428t-5.428 12.857v36.572q0 7.428 5.428 12.857t12.857 5.428h402.286q7.428 0 12.857-5.428t5.428-12.857zM438.857 242.286v-36.572q0-7.428-5.428-12.857t-12.857-5.428h-402.286q-7.428 0-12.857 5.428t-5.428 12.857v36.572q0 7.428 5.428 12.857t12.857 5.429h402.286q7.428 0 12.857-5.428t5.428-12.857zM438.857 388.572v-36.572q0-7.428-5.428-12.857t-12.857-5.429h-402.286q-7.428 0-12.857 5.428t-5.428 12.857v36.571q0 7.429 5.428 12.857t12.857 5.428h402.286q7.428 0 12.857-5.428t5.428-12.857z" horiz-adv-x="439" /> -<glyph unicode="" d="M340 314l83.714 83.714-30.572 30.572-83.714-83.714zM467.714 397.714q0-7.714-5.143-12.857l-367.428-367.428q-5.143-5.143-12.857-5.143t-12.857 5.143l-56.572 56.572q-5.143 5.143-5.143 12.857t5.143 12.857l367.428 367.428q5.143 5.143 12.857 5.143t12.857-5.143l56.572-56.572q5.143-5.143 5.143-12.857zM81.715 452l28-8.572-28-8.572-8.572-28-8.572 28-28 8.572 28 8.572 8.572 28zM181.714 405.714l56-17.143-56-17.143-17.143-56-17.143 56-56 17.143 56 17.143 17.143 56zM447.428 269.143l28-8.572-28-8.572-8.572-28-8.572 28-28 8.572 28 8.572 8.572 28zM264.572 452l28-8.572-28-8.572-8.572-28-8.572 28-28 8.572 28 8.572 8.572 28z" horiz-adv-x="476" /> -<glyph unicode="" d="M512 123.428v-91.428q0-11.428-8-19.428t-19.428-8h-91.428q-11.428 0-19.428 8t-8 19.428v91.428q0 11.428 8 19.428t19.428 8h27.428v54.857h-146.286v-54.857h27.428q11.428 0 19.428-8t8-19.428v-91.428q0-11.428-8-19.428t-19.428-8h-91.428q-11.428 0-19.428 8t-8 19.428v91.428q0 11.428 8 19.428t19.428 8h27.428v54.857h-146.286v-54.857h27.428q11.428 0 19.428-8t8-19.428v-91.428q0-11.428-8-19.428t-19.428-8h-91.428q-11.428 0-19.428 8t-8 19.428v91.428q0 11.428 8 19.428t19.428 8h27.428v54.857q0 14.857 10.857 25.714t25.715 10.857h146.286v54.857h-27.428q-11.428 0-19.428 8t-8 19.428v91.428q0 11.428 8 19.428t19.428 8h91.428q11.428 0 19.428-8t8-19.428v-91.428q0-11.428-8-19.428t-19.428-8h-27.428v-54.857h146.286q14.857 0 25.714-10.857t10.857-25.714v-54.857h27.428q11.428 0 19.428-8t8-19.428z" /> -<glyph unicode="" d="M512 141.714v-54.857q0-3.714-2.714-6.428t-6.428-2.714h-393.143v-54.857q0-3.714-2.715-6.428t-6.428-2.714q-3.428 0-6.857 2.857l-91.143 91.428q-2.571 2.572-2.571 6.286 0 4 2.571 6.572l91.428 91.428q2.572 2.572 6.572 2.572 3.715 0 6.428-2.714t2.715-6.428v-54.857h393.143q3.714 0 6.428-2.714t2.714-6.428zM512 297.143q0-4-2.572-6.572l-91.428-91.428q-2.572-2.572-6.572-2.572-3.714 0-6.428 2.714t-2.714 6.428v54.857h-393.143q-3.715 0-6.428 2.714t-2.715 6.429v54.857q0 3.714 2.715 6.428t6.428 2.714h393.143v54.857q0 4 2.572 6.571t6.572 2.572q3.428 0 6.857-2.857l91.143-91.143q2.572-2.571 2.572-6.572z" /> -<glyph unicode="" d="M109.715 96q0-7.428-5.428-12.857t-12.857-5.428-12.857 5.428-5.428 12.857 5.428 12.857 12.857 5.428 12.857-5.428 5.428-12.857zM402.286 78.572q0-34.572-20.857-54.286t-55.428-19.714h-249.714q-34.572 0-55.428 19.714t-20.857 54.286q0 19.428 1.571 37.428t6.857 39.428 13.572 37.857 23.143 29.428 34.285 17.286q-6.285-14.857-6.285-34.286v-58q-16.572-5.714-26.572-20t-10-31.714q0-22.857 16-38.857t38.857-16 38.857 16 16 38.857q0 17.428-10.143 31.714t-26.428 20v58q0 17.714 7.143 26.572 37.715-29.714 84.285-29.714t84.285 29.714q7.143-8.857 7.143-26.572v-18.286q-30.286 0-51.714-21.428t-21.428-51.714v-25.428q-9.143-8.286-9.143-20.286 0-11.428 8-19.428t19.429-8 19.428 8 8 19.428q0 12-9.143 20.286v25.428q0 14.857 10.857 25.714t25.714 10.857 25.714-10.857 10.857-25.714v-25.428q-9.143-8.286-9.143-20.286 0-11.428 8-19.428t19.428-8 19.428 8 8 19.428q0 12-9.143 20.286v25.428q0 19.428-9.857 36.428t-26.714 26.714q0 2.857 0.143 12.143t0 13.714-0.714 11.857-2 13.428-3.714 11.428q19.428-4.286 34.286-17.286t23.143-29.428 13.572-37.857 6.857-39.428 1.572-37.428zM310.857 333.714q0-45.428-32.143-77.572t-77.572-32.143-77.572 32.143-32.143 77.571 32.143 77.572 77.572 32.143 77.572-32.143 32.143-77.572z" horiz-adv-x="403" /> -<glyph unicode="" d="M365.714 224q0 29.714-11.572 56.714t-31.286 46.714-46.714 31.286-56.714 11.571-56.714-11.571-46.715-31.286-31.285-46.714-11.572-56.714 11.572-56.714 31.285-46.714 46.715-31.286 56.714-11.572 56.714 11.572 46.714 31.286 31.286 46.714 11.572 56.714zM438.857 224q0-59.714-29.428-110.143t-79.857-79.857-110.143-29.428-110.143 29.428-79.857 79.857-29.428 110.143 29.428 110.143 79.857 79.857 110.143 29.428 110.143-29.428 79.857-79.857 29.428-110.143z" horiz-adv-x="439" /> -<glyph unicode="" d="M141.714 96q0-17.143-12.143-29.143t-29-12q-17.143 0-29.143 12t-12 29.143 12 29.143 29.143 12q16.857 0 29-12t12.143-29.143zM265.143 41.143q0-15.143-10.714-25.857t-25.857-10.714-25.857 10.714-10.714 25.857 10.714 25.857 25.857 10.714 25.857-10.714 10.714-25.857zM91.428 224q0-18.857-13.428-32.286t-32.285-13.428-32.285 13.428-13.428 32.286 13.428 32.286 32.285 13.428 32.285-13.428 13.428-32.286zM388.572 96q0-13.143-9.428-22.572t-22.572-9.428-22.572 9.428-9.428 22.572 9.428 22.572 22.572 9.428 22.572-9.428 9.428-22.572zM150.857 352q0-20.857-14.714-35.572t-35.572-14.714-35.572 14.714-14.715 35.572 14.715 35.572 35.572 14.714 35.572-14.714 14.714-35.572zM283.428 406.857q0-22.857-16-38.857t-38.857-16-38.857 16-16 38.857 16 38.857 38.857 16 38.857-16 16-38.857zM438.857 224q0-11.428-8-19.428t-19.428-8-19.428 8-8 19.428 8 19.428 19.428 8 19.428-8 8-19.428zM379.428 352q0-9.428-6.714-16.143t-16.143-6.714-16.143 6.714-6.714 16.143 6.714 16.143 16.143 6.714 16.143-6.714 6.714-16.143z" horiz-adv-x="448" /> -<glyph unicode="" d="M438.857 224q0-59.714-29.428-110.143t-79.857-79.857-110.143-29.428-110.143 29.428-79.857 79.857-29.428 110.143 29.428 110.143 79.857 79.857 110.143 29.428 110.143-29.428 79.857-79.857 29.428-110.143z" horiz-adv-x="439" /> +<font id="icomoon" horiz-adv-x="1024"> +<font-face units-per-em="1024" ascent="960" descent="-64" /> +<missing-glyph horiz-adv-x="1024" /> +<glyph unicode=" " d="" horiz-adv-x="512" /> +<glyph unicode="" d="M887.048 801.673c0 3.001-0.375 30.379-14.251 57.759-19.878 39.755-57.382 61.883-105.39 61.883h-113.641v10.876c0 0 0 26.254-26.254 26.254l-241.159-0.375c0 0-26.254 0-26.254-26.254v-10.876h-113.641c-3.001 0-30.379-0.375-58.134-14.251-39.381-20.628-61.509-58.134-61.134-106.14l1.125-742.979c0-3.001 0.375-30.379 14.251-57.759 19.878-39.755 57.382-61.509 105.39-61.509l520.948 0.75c3.001 0 30.379 0.375 58.134 14.251 39.755 19.878 61.509 57.382 61.509 105.39l-1.5 742.979zM797.787 14.815c-13.503-7.126-28.129-7.876-29.254-7.876l-520.573-0.75c-28.505 0-38.63 13.126-43.881 22.502-7.126 13.503-7.876 28.129-7.876 29.254l-1.5 742.603c0 28.505 12.751 38.63 22.502 43.881 13.503 7.126 28.129 7.876 29.254 7.876h113.266v-11.626c0 0 0-26.254 26.254-26.254l240.783 0.375c0 0 26.254 0 26.254 26.254v11.626h113.641c28.505 0 38.63-12.751 43.881-22.502 7.126-13.503 7.876-28.129 7.876-29.254l1.125-742.603c1.125-28.129-12.001-38.255-21.754-43.506zM706.274 588.269c0 0-20.252 20.252-40.881 0l-192.402-192.777-103.89 103.515c0 0-20.252 20.252-40.881 0l-31.505-31.505c0 0-20.252-20.252 0-40.881l156.022-155.272c0 0 7.876-7.876 19.127-9.002 6.751-0.75 14.251 1.5 21.754 9.002l244.16 244.909c0 0 20.252 20.252 0 40.881l-31.505 31.129z" horiz-adv-x="1072" /> +<glyph unicode="" d="M658.286 484.572q0 105.714-75.144 180.856t-180.856 75.144-180.856-75.144-75.144-180.856 75.144-180.856 180.856-75.144 180.856 75.144 75.144 180.856zM950.856 9.144q0-29.714-21.714-51.428t-51.428-21.714q-30.856 0-51.428 21.714l-196 195.428q-102.286-70.856-228-70.856-81.714 0-156.286 31.714t-128.57 85.714-85.714 128.572-31.714 156.286 31.714 156.286 85.714 128.572 128.57 85.714 156.286 31.714 156.286-31.714 128.572-85.714 85.714-128.572 31.714-156.286q0-125.714-70.856-228l196-196q21.144-21.144 21.144-51.428z" horiz-adv-x="952" /> +<glyph unicode="" d="M954.856 636.572q0-22.856-16-38.856l-491.428-491.428q-16-16-38.856-16t-38.856 16l-284.572 284.572q-16 16-16 38.856t16 38.856l77.714 77.714q16 16 38.856 16t38.856-16l168-168.572 374.858 375.428q16 16 38.856 16t38.856-16l77.714-77.714q16-16 16-38.858z" /> +<glyph unicode="" d="M741.714 204.572q0-22.856-16-38.856l-77.714-77.714q-16-16-38.856-16t-38.856 16l-168 168-168-168q-16-16-38.856-16t-38.856 16l-77.714 77.714q-16 16-16 38.856t16 38.856l168 168-168 168q-16 16-16 38.856t16 38.856l77.714 77.714q16 16 38.856 16t38.856-16l168-168 168 168q16 16 38.856 16t38.856-16l77.714-77.714q16-16 16-38.856t-16-38.856l-168-168 168-168q16-16 16-38.856z" horiz-adv-x="806" /> +<glyph unicode="" d="M877.714 448q0-89.144-34.856-170.286t-93.714-140-140-93.714-170.286-34.856-170.286 34.856-140 93.714-93.714 140-34.856 170.286q0 104 46 196t129.43 154.286q24.57 18.286 54.57 14.286t47.714-28.572q18.286-24 14-54t-28.286-48.286q-56-42.286-86.57-103.428t-30.57-130.286q0-59.43 23.144-113.43t62.57-93.428 93.43-62.572 113.428-23.144 113.428 23.144 93.428 62.572 62.572 93.428 23.144 113.428q0 69.144-30.572 130.286t-86.572 103.428q-24 18.286-28.286 48.286t14 54q17.714 24.572 48 28.572t54.286-14.286q83.428-62.286 129.428-154.286t46-196zM512 886.856v-365.714q0-29.714-21.714-51.428t-51.43-21.714-51.428 21.714-21.714 51.428v365.714q0 29.714 21.714 51.43t51.428 21.714 51.428-21.714 21.714-51.43z" horiz-adv-x="878" /> +<glyph unicode="" d="M585.144 448q0 60.572-42.856 103.428t-103.428 42.856-103.428-42.856-42.856-103.428 42.856-103.428 103.428-42.856 103.428 42.856 42.856 103.428zM877.714 510.286v-126.858q0-6.856-4.572-13.144t-11.428-7.428l-105.714-16q-10.856-30.856-22.286-52 20-28.572 61.144-78.856 5.714-6.856 5.714-14.286t-5.144-13.144q-15.428-21.144-56.572-61.714t-53.714-40.572q-6.856 0-14.856 5.144l-78.856 61.714q-25.144-13.144-52-21.714-9.144-77.714-16.572-106.286-4-16-20.572-16h-126.856q-8 0-14 4.856t-6.572 12.286l-16 105.144q-28 9.144-51.428 21.144l-80.57-61.144q-5.714-5.144-14.286-5.144-8 0-14.286 6.286-72 65.144-94.286 96-4 5.714-4 13.144 0 6.856 4.57 13.144 8.57 12 29.144 38t30.856 40.286q-15.43 28.572-23.43 56.572l-104.57 15.428q-7.43 1.144-12 7.144t-4.57 13.428v126.856q0 6.858 4.57 13.144t10.856 7.428l106.286 16q8 26.286 22.286 52.572-22.856 32.572-61.144 78.856-5.714 6.858-5.714 13.714 0 5.714 5.144 13.142 14.856 20.572 56.286 61.428t54 40.858q7.43 0 14.856-5.714l78.856-61.144q25.144 13.144 52 21.714 9.144 77.714 16.572 106.286 4 16 20.572 16h126.856q8 0 14-4.856t6.572-12.286l16-105.144q28-9.144 51.428-21.144l81.144 61.144q5.144 5.144 13.714 5.144 7.428 0 14.286-5.714 73.714-68 94.286-97.144 4-4.57 4-12.57 0-6.858-4.572-13.144-8.572-12-29.144-38t-30.856-40.286q14.856-28.57 23.428-56l104.572-16q7.428-1.142 12-7.142t4.572-13.428z" horiz-adv-x="878" /> +<glyph unicode="" d="M292.572 539.428v-329.142q0-8-5.142-13.144t-13.142-5.144h-36.57q-8 0-13.144 5.144t-5.144 13.144v329.144q0 8 5.144 13.142t13.144 5.142h36.57q8 0 13.144-5.142t5.142-13.144zM438.858 539.428v-329.142q0-8-5.142-13.144t-13.144-5.144h-36.572q-8 0-13.144 5.144t-5.142 13.144v329.144q0 8 5.142 13.142t13.144 5.142h36.572q8 0 13.144-5.142t5.142-13.144zM585.144 539.428v-329.142q0-8-5.144-13.144t-13.144-5.144h-36.572q-8 0-13.144 5.144t-5.142 13.144v329.144q0 8 5.142 13.142t13.144 5.142h36.572q8 0 13.144-5.142t5.144-13.144zM658.286 125.714v541.714h-512v-541.714q0-12.572 4-23.144t8.286-15.428 6-4.856h475.43q1.714 0 6 4.856t8.286 15.428 4 23.144zM274.286 740.572h256l-27.428 66.856q-4 5.144-9.714 6.286h-181.142q-5.714-1.142-9.714-6.286zM804.572 722.286v-36.572q0-8-5.144-13.144t-13.144-5.142h-54.856v-541.714q0-47.428-26.856-82t-64.572-34.572h-475.428q-37.714 0-64.57 33.428t-26.856 80.856v544h-54.856q-8 0-13.144 5.144t-5.142 13.142v36.572q0 8 5.142 13.144t13.144 5.142h176.57l40 95.428q8.57 21.144 30.858 36t45.144 14.858h182.856q22.856 0 45.144-14.858t30.856-36l40-95.428h176.572q8 0 13.144-5.142t5.144-13.144z" horiz-adv-x="806" /> +<glyph unicode="" d="M621.714 429.714v-36.572q0-7.428-5.428-12.856t-12.856-5.428h-219.428q-7.428 0-12.856 5.428t-5.428 12.856v256q0 7.428 5.428 12.856t12.856 5.428h36.572q7.428 0 12.856-5.428t5.428-12.856v-201.144h164.572q7.428 0 12.856-5.428t5.428-12.856zM731.428 448q0 59.428-23.144 113.428t-62.572 93.428-93.428 62.572-113.428 23.142-113.428-23.142-93.43-62.572-62.57-93.428-23.144-113.428 23.144-113.428 62.57-93.428 93.43-62.572 113.428-23.144 113.428 23.144 93.428 62.572 62.572 93.428 23.144 113.428zM877.714 448q0-119.428-58.856-220.286t-159.714-159.714-220.286-58.856-220.286 58.856-159.714 159.714-58.856 220.286 58.856 220.286 159.714 159.714 220.286 58.856 220.286-58.856 159.714-159.714 58.856-220.286z" horiz-adv-x="878" /> +<glyph unicode="" d="M863.428 356.572q0-2.856-0.572-4-36.572-153.144-153.144-248.286t-273.142-95.144q-83.43 0-161.43 31.428t-139.144 89.714l-73.714-73.714q-10.856-10.856-25.714-10.856t-25.714 10.856-10.856 25.714v256q0 14.856 10.856 25.714t25.714 10.856h256q14.856 0 25.714-10.856t10.858-25.714-10.856-25.714l-78.286-78.286q40.57-37.714 92-58.286t106.858-20.572q76.572 0 142.856 37.144t106.286 102.286q6.286 9.714 30.286 66.856 4.572 13.144 17.144 13.144h109.714q7.428 0 12.856-5.428t5.428-12.856zM877.714 813.714v-256q0-14.856-10.856-25.714t-25.714-10.856h-256q-14.856 0-25.714 10.856t-10.856 25.714 10.856 25.714l78.856 78.856q-84.572 78.286-199.428 78.286-76.572 0-142.856-37.142t-106.286-102.286q-6.286-9.714-30.286-66.858-4.57-13.144-17.144-13.144h-113.714q-7.43 0-12.856 5.428t-5.43 12.856v4q37.144 153.144 154.286 248.286t274.286 95.142q83.428 0 162.286-31.714t140-89.428l74.286 73.714q10.856 10.856 25.714 10.856t25.714-10.856 10.856-25.714z" horiz-adv-x="878" /> +<glyph unicode="" d="M402.286 374.856q0 30.286-21.428 51.714t-51.714 21.428-51.714-21.428-21.428-51.714q0-21.144 10.858-38.286t29.144-26.856l-39.428-130.856q-2.856-8.572 2.858-16t14.858-7.428h109.714q9.142 0 14.858 7.428t2.858 16l-39.43 130.856q18.286 9.714 29.144 26.856t10.856 38.286zM182.856 521.144h292.572v109.714q0 60.572-42.856 103.428t-103.428 42.858-103.43-42.858-42.856-103.428v-109.714zM658.286 466.286v-329.142q0-22.856-16-38.856t-38.856-16h-548.572q-22.856 0-38.856 16t-16 38.856v329.142q0 22.858 16 38.858t38.856 16h18.286v109.714q0 105.144 75.43 180.572t180.57 75.428 180.57-75.428 75.428-180.572v-109.714h18.286q22.856 0 38.856-16t16-38.856z" horiz-adv-x="658" /> +<glyph unicode="" d="M665.144 886.856q13.144 0 25.144-5.144 18.856-7.428 30-23.428t11.144-35.428v-736.572q0-19.428-11.144-35.428t-30-23.428q-10.856-4.572-25.144-4.572-27.428 0-47.428 18.286l-252 242.286-252-242.286q-20.57-18.856-47.43-18.856-13.144 0-25.144 5.144-18.856 7.428-30 23.428t-11.144 35.428v736.572q0 19.428 11.144 35.428t30 23.43q12 5.142 25.144 5.142h598.856z" horiz-adv-x="732" /> +<glyph unicode="" d="M585.144 173.714v36.572q0 8-5.144 13.144t-13.144 5.144h-54.856v274.286q0 8-5.142 13.142t-13.142 5.142h-182.856q-8 0-13.144-5.142t-5.142-13.144v-36.572q0-8 5.142-13.144t13.144-5.142h54.856v-219.43h-54.856q-8 0-13.144-5.144t-5.142-13.144v-36.572q0-8 5.142-13.144t13.144-5.144h256q8 0 13.144 5.144t5.144 13.144zM512 612.572v109.714q0 8-5.142 13.142t-13.142 5.144h-109.714q-8 0-13.142-5.144t-5.142-13.142v-109.714q0-8 5.142-13.144t13.144-5.142h109.714q8 0 13.142 5.142t5.144 13.144zM877.714 448q0-119.428-58.856-220.286t-159.714-159.714-220.286-58.856-220.286 58.856-159.714 159.714-58.856 220.286 58.856 220.286 159.714 159.714 220.286 58.856 220.286-58.856 159.714-159.714 58.856-220.286z" horiz-adv-x="878" /> +<glyph unicode="" d="M684 374.856h-62.286q-14.856 0-25.714 10.856t-10.856 25.714v73.144q0 14.856 10.856 25.714t25.714 10.858h62.286q-18.286 61.714-64.286 107.714t-107.714 64.286v-62.286q0-14.858-10.858-25.714t-25.714-10.856h-73.142q-14.856 0-25.714 10.856t-10.858 25.714v62.286q-61.714-18.286-107.714-64.286t-64.286-107.714h62.286q14.858 0 25.714-10.856t10.856-25.714v-73.142q0-14.856-10.856-25.714t-25.714-10.856h-62.286q18.286-61.714 64.286-107.714t107.714-64.286v62.286q0 14.856 10.856 25.714t25.714 10.856h73.142q14.856 0 25.714-10.856t10.858-25.714v-62.286q61.714 18.286 107.714 64.286t64.286 107.714zM877.714 484.572v-73.144q0-14.856-10.856-25.714t-25.714-10.856h-81.714q-21.144-92-88.286-159.144t-159.144-88.286v-81.714q0-14.856-10.856-25.714t-25.714-10.856h-73.142q-14.856 0-25.714 10.856t-10.858 25.714v81.714q-92 21.144-159.144 88.286t-88.286 159.144h-81.714q-14.856 0-25.714 10.856t-10.856 25.714v73.144q0 14.856 10.856 25.714t25.714 10.858h81.714q21.144 92 88.286 159.144t159.144 88.286v81.714q0 14.856 10.856 25.714t25.714 10.856h73.142q14.856 0 25.714-10.856t10.858-25.714v-81.714q92-21.142 159.144-88.286t88.286-159.144h81.714q14.856 0 25.714-10.856t10.856-25.714z" horiz-adv-x="878" /> +<glyph unicode="" d="M731.428 448q0 79.428-40.572 148.572l-400.572-400.572q69.144-40.572 148.572-40.572 59.428 0 113.428 23.144t93.428 62.572 62.572 93.428 23.144 113.428zM186.856 299.428l400.572 400.572q-69.144 40.572-148.572 40.572-59.428 0-113.428-23.144t-93.43-62.572-62.57-93.428-23.144-113.428q0-79.428 40.57-148.572zM877.714 448q0-119.428-58.856-220.286t-159.714-159.714-220.286-58.856-220.286 58.856-159.714 159.714-58.856 220.286 58.856 220.286 159.714 159.714 220.286 58.856 220.286-58.856 159.714-159.714 58.856-220.286z" horiz-adv-x="878" /> +<glyph unicode="" d="M431.428 356.572q0-7.428-5.714-13.144l-189.714-189.714 82.286-82.286q10.858-10.856 10.858-25.714t-10.856-25.714-25.714-10.856h-256q-14.856 0-25.714 10.856t-10.856 25.714v256q0 14.856 10.856 25.714t25.714 10.856 25.714-10.856l82.286-82.286 189.714 189.714q5.714 5.714 13.144 5.714t13.144-5.714l65.144-65.144q5.714-5.714 5.714-13.144zM877.714 850.286v-256q0-14.858-10.856-25.714t-25.714-10.856-25.714 10.856l-82.286 82.286-189.714-189.714q-5.714-5.714-13.144-5.714t-13.144 5.714l-65.144 65.144q-5.714 5.714-5.714 13.144t5.714 13.144l189.714 189.714-82.286 82.286q-10.856 10.856-10.856 25.714t10.856 25.714 25.714 10.856h256q14.856 0 25.714-10.856t10.856-25.714z" horiz-adv-x="878" /> +<glyph unicode="" d="M438.858 411.428v-256q0-14.856-10.858-25.714t-25.714-10.856-25.714 10.856l-82.286 82.286-189.714-189.714q-5.714-5.714-13.144-5.714t-13.144 5.714l-65.144 65.144q-5.714 5.714-5.714 13.144t5.714 13.144l189.714 189.714-82.286 82.286q-10.856 10.856-10.856 25.714t10.856 25.714 25.714 10.856h256q14.856 0 25.714-10.856t10.858-25.714zM870.286 795.428q0-7.428-5.714-13.142l-189.714-189.714 82.286-82.286q10.856-10.858 10.856-25.714t-10.856-25.714-25.714-10.858h-256q-14.856 0-25.714 10.856t-10.858 25.714v256q0 14.858 10.856 25.714t25.714 10.856 25.714-10.856l82.286-82.286 189.714 189.714q5.714 5.714 13.144 5.714t13.144-5.714l65.144-65.144q5.714-5.714 5.714-13.144z" horiz-adv-x="878" /> +<glyph unicode="" d="M438.858 886.856q119.43 0 220.286-58.856t159.714-159.714 58.856-220.286-58.856-220.286-159.714-159.714-220.286-58.856-220.286 58.856-159.714 159.714-58.856 220.286 58.856 220.286 159.714 159.714 220.286 58.856zM512 174.286v108.572q0 8-5.142 13.428t-12.572 5.428h-109.714q-7.428 0-13.144-5.714t-5.714-13.144v-108.572q0-7.428 5.714-13.144t13.144-5.714h109.714q7.428 0 12.572 5.428t5.142 13.428zM510.858 370.856l10.286 354.856q0 6.858-5.714 10.286-5.714 4.572-13.714 4.572h-125.714q-8 0-13.714-4.572-5.714-3.428-5.714-10.286l9.714-354.856q0-5.714 5.714-10t13.714-4.286h105.714q8 0 13.428 4.286t6 10z" horiz-adv-x="878" /> +<glyph unicode="" d="M585.144 174.286v108.572q0 8-5.428 13.428t-12.856 5.428h-109.714q-7.428 0-12.858-5.428t-5.428-13.428v-108.572q0-8 5.428-13.428t12.856-5.428h109.714q7.428 0 12.856 5.428t5.428 13.428zM584 388l10.286 262.286q0 6.856-5.714 10.856-7.428 6.286-13.714 6.286h-125.714q-6.286 0-13.714-6.286-5.714-4-5.714-12l9.714-261.144q0-5.714 5.714-9.428t13.714-3.714h105.714q8 0 13.428 3.714t6 9.428zM576 921.714l438.856-804.57q20-36-1.144-72-9.714-16.572-26.572-26.286t-36.286-9.714h-877.714q-19.43 0-36.286 9.714t-26.572 26.286q-21.144 36-1.144 72l438.858 804.572q9.714 17.714 26.858 28t37.144 10.286 37.144-10.286 26.856-28z" /> +<glyph unicode="" d="M877.714 192v-73.144q0-14.856-10.856-25.714t-25.714-10.856h-804.572q-14.856 0-25.714 10.856t-10.856 25.714v73.144q0 14.856 10.856 25.714t25.714 10.856h804.572q14.856 0 25.714-10.856t10.856-25.714zM877.714 484.572v-73.144q0-14.856-10.856-25.714t-25.714-10.856h-804.572q-14.856 0-25.714 10.856t-10.856 25.714v73.144q0 14.856 10.856 25.714t25.714 10.858h804.572q14.856 0 25.714-10.856t10.856-25.714zM877.714 777.144v-73.144q0-14.856-10.856-25.714t-25.714-10.858h-804.572q-14.856 0-25.714 10.856t-10.856 25.714v73.142q0 14.858 10.856 25.714t25.714 10.856h804.572q14.856 0 25.714-10.856t10.856-25.714z" horiz-adv-x="878" /> +<glyph unicode="" d="M680 628l167.428 167.428-61.144 61.144-167.428-167.428zM935.428 795.428q0-15.428-10.286-25.714l-734.856-734.856q-10.286-10.286-25.714-10.286t-25.714 10.286l-113.144 113.144q-10.286 10.286-10.286 25.714t10.286 25.714l734.856 734.856q10.286 10.286 25.714 10.286t25.714-10.286l113.144-113.144q10.286-10.286 10.286-25.714zM163.43 904l56-17.144-56-17.144-17.144-56-17.144 56-56 17.144 56 17.144 17.144 56zM363.428 811.428l112-34.286-112-34.286-34.286-112-34.286 112-112 34.286 112 34.286 34.286 112zM894.856 538.286l56-17.144-56-17.144-17.144-56-17.144 56-56 17.144 56 17.144 17.144 56zM529.144 904l56-17.144-56-17.144-17.144-56-17.144 56-56 17.144 56 17.144 17.144 56z" horiz-adv-x="952" /> +<glyph unicode="" d="M1024 246.856v-182.856q0-22.856-16-38.856t-38.856-16h-182.856q-22.856 0-38.856 16t-16 38.856v182.856q0 22.856 16 38.856t38.856 16h54.856v109.714h-292.572v-109.714h54.856q22.856 0 38.856-16t16-38.856v-182.856q0-22.856-16-38.856t-38.856-16h-182.856q-22.856 0-38.856 16t-16 38.856v182.856q0 22.856 16 38.856t38.856 16h54.856v109.714h-292.572v-109.714h54.856q22.856 0 38.856-16t16-38.856v-182.856q0-22.856-16-38.856t-38.856-16h-182.856q-22.856 0-38.856 16t-16 38.856v182.856q0 22.856 16 38.856t38.856 16h54.856v109.714q0 29.714 21.714 51.428t51.43 21.714h292.572v109.714h-54.856q-22.856 0-38.856 16t-16 38.856v182.856q0 22.856 16 38.856t38.856 16h182.856q22.856 0 38.856-16t16-38.856v-182.856q0-22.856-16-38.856t-38.856-16h-54.856v-109.714h292.572q29.714 0 51.428-21.714t21.714-51.428v-109.714h54.856q22.856 0 38.856-16t16-38.856z" /> +<glyph unicode="" d="M1024 283.428v-109.714q0-7.428-5.428-12.856t-12.856-5.428h-786.286v-109.714q0-7.428-5.43-12.856t-12.856-5.428q-6.856 0-13.714 5.714l-182.286 182.856q-5.142 5.144-5.142 12.572 0 8 5.142 13.144l182.856 182.856q5.144 5.144 13.144 5.144 7.43 0 12.856-5.428t5.43-12.856v-109.714h786.286q7.428 0 12.856-5.428t5.428-12.856zM1024 594.286q0-8-5.144-13.144l-182.856-182.856q-5.144-5.144-13.144-5.144-7.428 0-12.856 5.428t-5.428 12.856v109.714h-786.286q-7.43 0-12.856 5.428t-5.43 12.858v109.714q0 7.428 5.43 12.856t12.856 5.428h786.286v109.714q0 8 5.144 13.142t13.144 5.144q6.856 0 13.714-5.714l182.286-182.286q5.144-5.142 5.144-13.144z" /> +<glyph unicode="" d="M219.43 192q0-14.856-10.856-25.714t-25.714-10.856-25.714 10.856-10.856 25.714 10.856 25.714 25.714 10.856 25.714-10.856 10.856-25.714zM804.572 157.144q0-69.144-41.714-108.572t-110.856-39.428h-499.428q-69.144 0-110.856 39.428t-41.714 108.572q0 38.856 3.142 74.856t13.714 78.856 27.144 75.714 46.286 58.856 68.57 34.572q-12.57-29.714-12.57-68.572v-116q-33.144-11.428-53.144-40t-20-63.428q0-45.714 32-77.714t77.714-32 77.714 32 32 77.714q0 34.856-20.286 63.428t-52.856 40v116q0 35.428 14.286 53.144 75.43-59.428 168.57-59.428t168.57 59.428q14.286-17.714 14.286-53.144v-36.572q-60.572 0-103.428-42.856t-42.856-103.428v-50.856q-18.286-16.572-18.286-40.572 0-22.856 16-38.856t38.858-16 38.856 16 16 38.856q0 24-18.286 40.572v50.856q0 29.714 21.714 51.428t51.428 21.714 51.428-21.714 21.714-51.428v-50.856q-18.286-16.572-18.286-40.572 0-22.856 16-38.856t38.856-16 38.856 16 16 38.856q0 24-18.286 40.572v50.856q0 38.856-19.714 72.856t-53.428 53.428q0 5.714 0.286 24.286t0 27.428-1.428 23.714-4 26.856-7.428 22.856q38.856-8.572 68.572-34.572t46.286-58.856 27.144-75.714 13.714-78.856 3.144-74.856zM621.714 667.428q0-90.856-64.286-155.144t-155.144-64.286-155.144 64.286-64.286 155.142 64.286 155.144 155.144 64.286 155.144-64.286 64.286-155.144z" horiz-adv-x="806" /> +<glyph unicode="" d="M731.428 448q0 59.428-23.144 113.428t-62.572 93.428-93.428 62.572-113.428 23.142-113.428-23.142-93.43-62.572-62.57-93.428-23.144-113.428 23.144-113.428 62.57-93.428 93.43-62.572 113.428-23.144 113.428 23.144 93.428 62.572 62.572 93.428 23.144 113.428zM877.714 448q0-119.428-58.856-220.286t-159.714-159.714-220.286-58.856-220.286 58.856-159.714 159.714-58.856 220.286 58.856 220.286 159.714 159.714 220.286 58.856 220.286-58.856 159.714-159.714 58.856-220.286z" horiz-adv-x="878" /> +<glyph unicode="" d="M283.428 192q0-34.286-24.286-58.286t-58-24q-34.286 0-58.286 24t-24 58.286 24 58.286 58.286 24q33.714 0 58-24t24.286-58.286zM530.286 82.286q0-30.286-21.428-51.714t-51.714-21.428-51.714 21.428-21.428 51.714 21.428 51.714 51.714 21.428 51.714-21.428 21.428-51.714zM182.856 448q0-37.714-26.856-64.572t-64.57-26.856-64.57 26.856-26.856 64.572 26.856 64.572 64.57 26.856 64.57-26.856 26.856-64.572zM777.144 192q0-26.286-18.856-45.144t-45.144-18.856-45.144 18.856-18.856 45.144 18.856 45.144 45.144 18.856 45.144-18.856 18.856-45.144zM301.714 704q0-41.714-29.428-71.144t-71.144-29.428-71.144 29.428-29.43 71.144 29.43 71.144 71.144 29.428 71.144-29.428 29.428-71.144zM566.856 813.714q0-45.714-32-77.714t-77.714-32-77.714 32-32 77.714 32 77.714 77.714 32 77.714-32 32-77.714zM877.714 448q0-22.856-16-38.856t-38.856-16-38.856 16-16 38.856 16 38.856 38.856 16 38.856-16 16-38.856zM758.856 704q0-18.856-13.428-32.286t-32.286-13.428-32.286 13.428-13.428 32.286 13.428 32.286 32.286 13.428 32.286-13.428 13.428-32.286z" horiz-adv-x="896" /> +<glyph unicode="" d="M877.714 448q0-119.428-58.856-220.286t-159.714-159.714-220.286-58.856-220.286 58.856-159.714 159.714-58.856 220.286 58.856 220.286 159.714 159.714 220.286 58.856 220.286-58.856 159.714-159.714 58.856-220.286z" horiz-adv-x="878" /> </font></defs></svg>
\ No newline at end of file diff --git a/client/src/com/vaadin/client/debug/internal/theme/font.ttf b/client/src/com/vaadin/client/debug/internal/theme/font.ttf Binary files differindex eee808e07e..734e69ac3f 100644..100755 --- a/client/src/com/vaadin/client/debug/internal/theme/font.ttf +++ b/client/src/com/vaadin/client/debug/internal/theme/font.ttf diff --git a/client/src/com/vaadin/client/debug/internal/theme/font.woff b/client/src/com/vaadin/client/debug/internal/theme/font.woff Binary files differindex 2cd069ffdf..a9e6d5576b 100644..100755 --- a/client/src/com/vaadin/client/debug/internal/theme/font.woff +++ b/client/src/com/vaadin/client/debug/internal/theme/font.woff diff --git a/client/src/com/vaadin/client/ui/VCalendar.java b/client/src/com/vaadin/client/ui/VCalendar.java index f0f1bc89ca..c59a78108c 100644 --- a/client/src/com/vaadin/client/ui/VCalendar.java +++ b/client/src/com/vaadin/client/ui/VCalendar.java @@ -588,7 +588,7 @@ public class VCalendar extends Composite implements VHasDropHandler { int x = pos - (y * columns); if (x == 0 && daysCount > 7) { // Add week to weekToolbar for navigation - weekToolbar.addWeek(week, d.getYear()); + weekToolbar.addWeek(week, day.getYearOfWeek()); } final SimpleDayCell cell = new SimpleDayCell(this, y, x); cell.setMonthGrid(monthGrid); diff --git a/client/src/com/vaadin/client/ui/VContextMenu.java b/client/src/com/vaadin/client/ui/VContextMenu.java index 1b0181fb7d..fa6d67fc0c 100644 --- a/client/src/com/vaadin/client/ui/VContextMenu.java +++ b/client/src/com/vaadin/client/ui/VContextMenu.java @@ -143,6 +143,9 @@ public class VContextMenu extends VOverlay implements SubPartAware { // context menu is closed focusedElement = Util.getFocusedElement(); + // reset height (if it has been previously set explicitly) + setHeight(""); + setPopupPositionAndShow(new PositionCallback() { @Override public void setPosition(int offsetWidth, int offsetHeight) { @@ -158,12 +161,10 @@ public class VContextMenu extends VOverlay implements SubPartAware { } } if (offsetHeight + top > Window.getClientHeight()) { - top = top - offsetHeight; - if (top < 0) { - top = 0; - - setHeight(Window.getClientHeight() + "px"); - } + top = Math.max(0, Window.getClientHeight() - offsetHeight); + } + if (top == 0) { + setHeight(Window.getClientHeight() + "px"); } setPopupPosition(left, top); diff --git a/client/src/com/vaadin/client/ui/VMenuBar.java b/client/src/com/vaadin/client/ui/VMenuBar.java index 4a090899f9..5102e6faea 100644 --- a/client/src/com/vaadin/client/ui/VMenuBar.java +++ b/client/src/com/vaadin/client/ui/VMenuBar.java @@ -245,7 +245,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * This is called by the items in the menu and it communicates the * information to the server - * + * * @param clickedItemId * id of the item that was clicked */ @@ -282,7 +282,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Returns the containing element of the menu - * + * * @return */ @Override @@ -292,7 +292,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Add a new item to this menu - * + * * @param html * items text * @param cmd @@ -309,7 +309,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Add a new item to this menu - * + * * @param item */ public void addItem(CustomMenuItem item) { @@ -334,7 +334,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Remove the given item from this menu - * + * * @param item */ public void removeItem(CustomMenuItem item) { @@ -431,7 +431,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * When an item is clicked - * + * * @param item */ public void itemClick(CustomMenuItem item) { @@ -462,7 +462,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * When the user hovers the mouse over the item - * + * * @param item */ public void itemOver(CustomMenuItem item) { @@ -487,7 +487,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * When the mouse is moved away from an item - * + * * @param item */ public void itemOut(CustomMenuItem item) { @@ -545,7 +545,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Shows the child menu of an item. The caller must ensure that the item has * a submenu. - * + * * @param item */ public void showChildMenu(CustomMenuItem item) { @@ -667,7 +667,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Hides the submenu of an item - * + * * @param item */ public void hideChildMenu(CustomMenuItem item) { @@ -731,7 +731,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Returns the parent menu of this menu, or null if this is the top-level * menu - * + * * @return */ public VMenuBar getParentMenu() { @@ -740,7 +740,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Set the parent menu of this menu - * + * * @param parent */ public void setParentMenu(VMenuBar parent) { @@ -750,7 +750,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Returns the currently selected item of this menu, or null if nothing is * selected - * + * * @return */ public CustomMenuItem getSelected() { @@ -759,7 +759,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Set the currently selected item of this menu - * + * * @param item */ public void setSelected(CustomMenuItem item) { @@ -776,9 +776,9 @@ public class VMenuBar extends SimpleFocusablePanel implements } /** - * + * * A class to hold information on menu items - * + * */ public static class CustomMenuItem extends Widget implements HasHTML { @@ -797,7 +797,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Default menu item {@link Widget} constructor for GWT.create(). - * + * * Use {@link #setHTML(String)} and {@link #setCommand(Command)} after * constructing a menu item. */ @@ -807,7 +807,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Creates a menu item {@link Widget}. - * + * * @param html * @param cmd * @deprecated use the default constructor and {@link #setHTML(String)} @@ -1041,7 +1041,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Checks if the item can be selected. - * + * * @return true if it is possible to select this item, false otherwise */ public boolean isSelectable() { @@ -1200,7 +1200,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection upwards. By default it is the up * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationUpKey() { @@ -1211,7 +1211,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection downwards. By default it is the down * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationDownKey() { @@ -1222,7 +1222,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection left. By default it is the left * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationLeftKey() { @@ -1233,7 +1233,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Get the key that moves the selection right. By default it is the right * arrow key but by overriding this you can change the key to whatever you * want. - * + * * @return The keycode of the key */ protected int getNavigationRightKey() { @@ -1243,7 +1243,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get the key that selects a menu item. By default it is the Enter key but * by overriding this you can change the key to whatever you want. - * + * * @deprecated use {@link #isNavigationSelectKey(int)} instead * @return */ @@ -1256,7 +1256,7 @@ public class VMenuBar extends SimpleFocusablePanel implements * Checks whether key code selects a menu item. By default it is the Enter * and Space keys but by overriding this you can change the keys to whatever * you want. - * + * * @since 7.2 * @param keycode * @return true if key selects menu item @@ -1269,7 +1269,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get the key that closes the menu. By default it is the escape key but by * overriding this yoy can change the key to whatever you want. - * + * * @return */ protected int getCloseMenuKey() { @@ -1278,7 +1278,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Handles the keyboard events handled by the MenuBar - * + * * @param event * The keyboard event received * @return true iff the navigation event was handled @@ -1565,12 +1565,31 @@ public class VMenuBar extends SimpleFocusablePanel implements private boolean isItemNamed(CustomMenuItem item, String name) { Element lastChildElement = getLastChildElement(item); - if (lastChildElement.getInnerText().equals(name)) { + if (getText(lastChildElement).equals(name)) { return true; } return false; } + /* + * Returns the text content of element without including the text of + * possible nested elements. It is assumed that the last child of element + * contains the text of interest and that the last child does not itself + * have children with text content. This method is used by + * getSubPartElement(String) so that possible text icons are not included in + * the textual matching (#14879). + */ + private native String getText(Element element) + /*-{ + var n = element.childNodes.length; + if(n > 0){ + return element.childNodes[n - 1].nodeValue; + } + else{ + return ""; + } + }-*/; + private Element getLastChildElement(CustomMenuItem item) { Element lastChildElement = item.getElement().getFirstChildElement(); while (lastChildElement.getNextSiblingElement() != null) { @@ -1604,7 +1623,7 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get menu item with given DOM element - * + * * @param element * Element used in search * @return Menu item or null if not found @@ -1633,11 +1652,11 @@ public class VMenuBar extends SimpleFocusablePanel implements /** * Get menu item with given DOM element - * + * * @param element * Element used in search * @return Menu item or null if not found - * + * * @since 7.2 */ public CustomMenuItem getMenuItemWithElement(Element element) { diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java index afa13dc337..dfd81faf94 100644 --- a/client/src/com/vaadin/client/ui/VOverlay.java +++ b/client/src/com/vaadin/client/ui/VOverlay.java @@ -79,6 +79,18 @@ import com.vaadin.client.Util; */ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { + @Override + protected void onAttach() { + // Move the overlay to the appropriate overlay container + final VOverlay overlay = VOverlay.current; + if (overlay != null) { + final Element e = overlay.getOverlayContainer(); + e.appendChild(getElement()); + } + + super.onAttach(); + } + public static class PositionAndSize { private int left, top, width, height; @@ -1061,4 +1073,5 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { } } } + } diff --git a/client/src/com/vaadin/client/ui/VPopupCalendar.java b/client/src/com/vaadin/client/ui/VPopupCalendar.java index 51b2ee22ec..fbd66cff09 100644 --- a/client/src/com/vaadin/client/ui/VPopupCalendar.java +++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java @@ -27,6 +27,10 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.DomEvent; 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.dom.client.MouseOverEvent; +import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.i18n.client.DateTimeFormat; @@ -60,7 +64,8 @@ import com.vaadin.shared.ui.datefield.Resolution; * */ public class VPopupCalendar extends VTextualDate implements Field, - ClickHandler, CloseHandler<PopupPanel>, SubPartAware { + ClickHandler, MouseOverHandler, MouseOutHandler, + CloseHandler<PopupPanel>, SubPartAware { /** For internal use only. May be removed or replaced in the future. */ public final Button calendarToggle = new Button(); @@ -75,6 +80,20 @@ public class VPopupCalendar extends VTextualDate implements Field, public boolean parsable = true; private boolean open = false; + /* + * To resolve #14857. If to click on calendarToggle button when calendar + * popup is opened (*1) then we have the following chain of calls: + * + * 1) onClose() 2) onClick() + * + * In this case we should prevent calling openCalendarPanel() in onClick. + */ + private boolean preventOpenPopupCalendar = false; + /* + * To resolve #14857. To determine this situation (*1) we use onMouseOver + * and OnMouseOut (for calendarToggle button). + */ + private boolean cursorOverCalendarToggleButton = false; private boolean textFieldEnabled = true; @@ -89,6 +108,10 @@ public class VPopupCalendar extends VTextualDate implements Field, calendarToggle.setText(""); calendarToggle.addClickHandler(this); + + calendarToggle.addMouseOverHandler(this); + calendarToggle.addMouseOutHandler(this); + // -2 instead of -1 to avoid FocusWidget.onAttach to reset it calendarToggle.getElement().setTabIndex(-2); @@ -441,7 +464,10 @@ public class VPopupCalendar extends VTextualDate implements Field, @Override public void onClick(ClickEvent event) { if (event.getSource() == calendarToggle && isEnabled()) { - openCalendarPanel(); + if (!preventOpenPopupCalendar) { + openCalendarPanel(); + } + preventOpenPopupCalendar = false; } } @@ -464,15 +490,22 @@ public class VPopupCalendar extends VTextualDate implements Field, focus(); } - // TODO resolve what the "Sigh." is all about and document it here - // Sigh. - Timer t = new Timer() { - @Override - public void run() { - open = false; - } - }; - t.schedule(100); + open = false; + + if (cursorOverCalendarToggleButton) { + preventOpenPopupCalendar = true; + + // To resolve the problem: onMouseOut event not triggered when + // moving mouse fast (GWT - all browsers) + Timer unPreventClickTimer = new Timer() { + @Override + public void run() { + preventOpenPopupCalendar = false; + } + }; + + unPreventClickTimer.schedule(300); + } } } @@ -642,4 +675,28 @@ public class VPopupCalendar extends VTextualDate implements Field, calendar.setRangeEnd(rangeEnd); } + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.MouseOverHandler#onMouseOver(com.google + * .gwt.event.dom.client.MouseOverEvent) + */ + @Override + public void onMouseOver(MouseOverEvent event) { + cursorOverCalendarToggleButton = true; + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.MouseOutHandler#onMouseOut(com.google + * .gwt.event.dom.client.MouseOutEvent) + */ + @Override + public void onMouseOut(MouseOutEvent event) { + cursorOverCalendarToggleButton = false; + } + } diff --git a/client/src/com/vaadin/client/ui/VPopupView.java b/client/src/com/vaadin/client/ui/VPopupView.java index 7d98110446..5b37a90915 100644 --- a/client/src/com/vaadin/client/ui/VPopupView.java +++ b/client/src/com/vaadin/client/ui/VPopupView.java @@ -195,6 +195,8 @@ public class VPopupView extends HTML implements HasEnabled, Iterable<Widget>, /** * Returns true if the popup is enabled, false if not. + * + * @since 7.3.4 */ @Override public boolean isEnabled() { @@ -206,6 +208,7 @@ public class VPopupView extends HTML implements HasEnabled, Iterable<Widget>, * * @param enabled <code>true</code> to enable the popup, <code>false</code> * to disable it + * @since 7.3.4 */ @Override public void setEnabled(boolean enabled) { @@ -439,6 +442,14 @@ public class VPopupView extends HTML implements HasEnabled, Iterable<Widget>, return Collections.singleton((Widget) popup).iterator(); } + /** + * Checks whether there are operations pending for this widget that must be + * executed before reaching a steady state. + * + * @returns <code>true</code> iff there are operations pending which must be + * executed before reaching a steady state + * @since 7.3.4 + */ @Override public boolean isWorkPending() { return popupShowInProgress; diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 42fef9f0c0..b07d2dc9c0 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -2600,11 +2600,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, @Override public void run() { + if (client.hasActiveRequest() || navKeyDown) { // if client connection is busy, don't bother loading it more VConsole.log("Postponed rowfetch"); schedule(250); - } else if (!updatedReqRows && allRenderedRowsAreNew()) { + } else if (allRenderedRowsAreNew() && !updatedReqRows) { /* * If all rows are new, there might have been a server-side call @@ -2625,6 +2626,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, setReqRows(last - getReqFirstRow() + 1); updatedReqRows = true; schedule(250); + } else { int firstRendered = scrollBody.getFirstRendered(); @@ -2712,6 +2714,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, client.updateVariable(paintableId, "firstvisible", firstRowInViewPort, false); } + client.updateVariable(paintableId, "reqfirstrow", reqFirstRow, false); client.updateVariable(paintableId, "reqrows", reqRows, true); @@ -3138,6 +3141,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, && Util.isTouchEventOrLeftMouseButton(event)) { dragging = false; DOM.releaseCapture(getElement()); + + if (Util.isTouchEvent(event)) { + /* + * Prevent using in e.g. scrolling and prevent generated + * events. + */ + event.preventDefault(); + event.stopPropagation(); + } if (moved) { hideFloatingCopy(); tHead.removeSlotFocus(); @@ -3149,14 +3161,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, reOrderColumn(cid, closestSlot); } } - } - if (Util.isTouchEvent(event)) { - /* - * Prevent using in e.g. scrolling and prevent generated - * events. - */ - event.preventDefault(); - event.stopPropagation(); + moved = false; + break; } } @@ -3630,6 +3636,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, c.setWidth(widthWithoutAddedIndent, true); } } else if (col.hasAttribute("er")) { + c.setUndefinedWidth(); c.setExpandRatio(col.getFloatAttribute("er")); } else if (recalcWidths) { @@ -4205,7 +4212,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } /** - * Returns the expand ration of the cell + * Returns the expand ratio of the cell * * @return The expand ratio */ @@ -4693,10 +4700,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } public int getLastRendered() { + return lastRendered; } public int getFirstRendered() { + return firstRendered; } @@ -4780,10 +4789,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } else if (firstIndex + rows == firstRendered) { final VScrollTableRow[] rowArray = new VScrollTableRow[rows]; int i = rows; + while (it.hasNext()) { i--; rowArray[i] = prepareRow((UIDL) it.next()); } + for (i = 0; i < rows; i++) { addRowBeforeFirstRendered(rowArray[i]); firstRendered--; @@ -4808,10 +4819,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, setLastRendered(lastRendered + 1); setContainerHeight(); fixSpacers(); + while (it.hasNext()) { addRow(prepareRow((UIDL) it.next())); setLastRendered(lastRendered + 1); } + fixSpacers(); } @@ -4826,6 +4839,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * has changed since the last request. */ protected void ensureCacheFilled() { + + /** + * Fixes cache issue #13576 where unnecessary rows are fetched + */ + if (isLazyScrollerActive()) { + return; + } + int reactFirstRow = (int) (firstRowInViewPort - pageLength * cache_react_rate); int reactLastRow = (int) (firstRowInViewPort + pageLength + pageLength @@ -6133,7 +6154,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, touchStart = event; Touch touch = event.getChangedTouches().get(0); // save position to fields, touches in events are same - // isntance during the operation. + // instance during the operation. touchStartX = touch.getClientX(); touchStartY = touch.getClientY(); /* @@ -6441,8 +6462,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, startRow = focusedRow; selectionRangeStart = focusedRow; // If start row is null then we have a multipage selection - // from - // above + // from above if (startRow == null) { startRow = (VScrollTableRow) scrollBody.iterator() .next(); @@ -7277,6 +7297,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } if (preLimit < firstRendered) { // need some rows to the beginning of the rendered area + rowRequestHandler .setReqFirstRow((int) (firstRowInViewPort - pageLength * cache_rate)); @@ -7662,13 +7683,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // viewport selectLastItemInNextRender = true; multiselectPending = shift; - scrollByPagelenght(1); + scrollByPagelength(1); } } } } else { /* No selections, go page down by scrolling */ - scrollByPagelenght(1); + scrollByPagelength(1); } return true; } @@ -7714,13 +7735,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // viewport selectFirstItemInNextRender = true; multiselectPending = shift; - scrollByPagelenght(-1); + scrollByPagelength(-1); } } } } else { /* No selections, go page up by scrolling */ - scrollByPagelenght(-1); + scrollByPagelength(-1); } return true; @@ -7794,7 +7815,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, .getRowHeight()); } - private void scrollByPagelenght(int i) { + private void scrollByPagelength(int i) { int pixels = i * scrollBodyPanel.getOffsetHeight(); int newPixels = scrollBodyPanel.getScrollPosition() + pixels; if (newPixels < 0) { diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index 9c3af5c568..bcca117395 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -512,6 +512,18 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware return (Tab) super.getWidget(index); } + private int getTabIndex(String tabId) { + if (tabId == null) { + return -1; + } + for (int i = 0; i < getTabCount(); i++) { + if (tabId.equals(getTab(i).id)) { + return i; + } + } + return -1; + } + public void selectTab(int index) { final Tab newSelected = getTab(index); final Tab oldSelected = selected; @@ -572,8 +584,40 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware if (tab == selected) { selected = null; } - // FIXME: Shouldn't something be selected instead? + + int scrollerIndexCandidate = getTabIndex(getTabsheet().scrollerPositionTabId); + if (scrollerIndexCandidate < 0) { + // The tab with id scrollerPositionTabId has been removed + scrollerIndexCandidate = getTabsheet().scrollerIndex; + } + scrollerIndexCandidate = selectNewShownTab(scrollerIndexCandidate); + if (scrollerIndexCandidate >= 0 + && scrollerIndexCandidate < getTabCount()) { + getTabsheet().scrollIntoView(getTab(scrollerIndexCandidate)); + } + } + + private int selectNewShownTab(int oldPosition) { + // After removing a tab, find a new scroll position. In most + // cases the scroll position does not change, but if the tab + // at the scroll position was removed, need to find a nearby + // tab that is visible. + for (int i = oldPosition; i < getTabCount(); i++) { + Tab tab = getTab(i); + if (!tab.isHiddenOnServer()) { + return i; + } + } + + for (int i = oldPosition - 1; i >= 0; i--) { + Tab tab = getTab(i); + if (!tab.isHiddenOnServer()) { + return i; + } + } + + return -1; } private boolean isFirstVisibleTab(int index) { @@ -685,6 +729,14 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware * The index of the first visible tab (when scrolled) */ private int scrollerIndex = 0; + /** + * The id of the tab at position scrollerIndex. This is used for keeping the + * scroll position unchanged when a tab is removed from the server side and + * the removed tab lies to the left of the current scroll position. For other + * cases scrollerIndex alone would be sufficient. Since the tab at the current + * scroll position can be removed, scrollerIndex is required in addition to this variable. + */ + private String scrollerPositionTabId; final TabBar tb = new TabBar(this); /** For internal use only. May be removed or replaced in the future. */ @@ -694,6 +746,9 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware private final Element deco; + /** For internal use only. May be removed or replaced in the future. */ + public boolean waitingForResponse; + private String currentStyle; /** @@ -701,7 +756,8 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware */ private boolean canSelectTab(final int tabIndex) { Tab tab = tb.getTab(tabIndex); - if (getApplicationConnection() == null || disabled) { + if (getApplicationConnection() == null || disabled + || waitingForResponse) { return false; } if (!tab.isEnabledOnServer() || tab.isHiddenOnServer()) { @@ -735,6 +791,8 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware getRpcProxy().setSelected(tabKeys.get(tabIndex).toString()); + waitingForResponse = true; + tb.getTab(tabIndex).focus(); // move keyboard focus to active tab return true; @@ -905,6 +963,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware if (newFirstIndex != -1) { scrollerIndex = newFirstIndex; + scrollerPositionTabId = tb.getTab(scrollerIndex).id; updateTabScroller(); } @@ -1200,6 +1259,8 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware /** For internal use only. May be removed or replaced in the future. */ public void showAllTabs() { scrollerIndex = tb.getFirstVisibleTab(); + scrollerPositionTabId = scrollerIndex < 0 ? null : tb + .getTab(scrollerIndex).id; for (int i = 0; i < tb.getTabCount(); i++) { Tab t = tb.getTab(i); if (!t.isHiddenOnServer()) { @@ -1774,12 +1835,18 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware } updateTabScroller(); } + if (scrollerIndex >= 0 && scrollerIndex < tb.getTabCount()) { + scrollerPositionTabId = tb.getTab(scrollerIndex).id; + } + else{ + scrollerPositionTabId = null; + } } } /** * Makes tab bar visible. - * + * * @since 7.2 */ public void showTabs() { diff --git a/client/src/com/vaadin/client/ui/VUpload.java b/client/src/com/vaadin/client/ui/VUpload.java index f234ef6d65..42fb08fb3c 100644 --- a/client/src/com/vaadin/client/ui/VUpload.java +++ b/client/src/com/vaadin/client/ui/VUpload.java @@ -184,7 +184,7 @@ public class VUpload extends SimplePanel { /** For internal use only. May be removed or replaced in the future. */ public void disableUpload() { - submitButton.setEnabled(false); + setEnabledForSubmitButton(false); if (!submitted) { // Cannot disable the fileupload while submitting or the file won't // be submitted at all @@ -195,7 +195,7 @@ public class VUpload extends SimplePanel { /** For internal use only. May be removed or replaced in the future. */ public void enableUpload() { - submitButton.setEnabled(true); + setEnabledForSubmitButton(true); fu.getElement().setPropertyBoolean("disabled", false); enabled = true; if (submitted) { @@ -209,6 +209,12 @@ public class VUpload extends SimplePanel { } } + private void setEnabledForSubmitButton(boolean enabled) { + submitButton.setEnabled(enabled); + submitButton.setStyleName(ApplicationConnection.DISABLED_CLASSNAME, + !enabled); + } + /** * Re-creates file input field and populates panel. This is needed as we * want to clear existing values from our current file input field. diff --git a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java index cbf63768a3..8f5e9d9a59 100644 --- a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java +++ b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java @@ -675,7 +675,7 @@ public class CalendarConnector extends AbstractComponentConnector implements List<CalendarDay> list = new ArrayList<CalendarDay>(days.size()); for (CalendarState.Day day : days) { CalendarDay d = new CalendarDay(day.date, day.localizedDateFormat, - day.dayOfWeek, day.week); + day.dayOfWeek, day.week, day.yearOfWeek); list.add(d); } diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java b/client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java index 44b82f166f..0fceb6b6f9 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java @@ -27,14 +27,16 @@ public class CalendarDay { private String localizedDateFormat; private int dayOfWeek; private int week; + private int yearOfWeek; public CalendarDay(String date, String localizedDateFormat, int dayOfWeek, - int week) { + int week, int yearOfWeek) { super(); this.date = date; this.localizedDateFormat = localizedDateFormat; this.dayOfWeek = dayOfWeek; this.week = week; + this.yearOfWeek = yearOfWeek; } public String getDate() { @@ -52,4 +54,8 @@ public class CalendarDay { public int getWeek() { return week; } + + public int getYearOfWeek() { + return yearOfWeek; + } } diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java index 8e83dc4e36..db8452af9a 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java @@ -74,8 +74,15 @@ public class SimpleDayCell extends FocusableFlowPanel implements private int startY = -1; private int startYrelative; private int startXrelative; - private Date startDateFrom; - private Date startDateTo; + // "from" date of date which is source of Dnd + private Date dndSourceDateFrom; + // "to" date of date which is source of Dnd + private Date dndSourceDateTo; + // "from" time of date which is source of Dnd + private Date dndSourceStartDateTime; + // "to" time of date which is source of Dnd + private Date dndSourceEndDateTime; + private int prevDayDiff = 0; private int prevWeekDiff = 0; private HandlerRegistration moveRegistration; @@ -392,8 +399,7 @@ public class SimpleDayCell extends FocusableFlowPanel implements prevDayDiff = 0; prevWeekDiff = 0; - if (!mel.isTimeSpecificEvent() - && (xDiff < -3 || xDiff > 3 || yDiff < -3 || yDiff > 3)) { + if (xDiff < -3 || xDiff > 3 || yDiff < -3 || yDiff > 3) { eventMoved(moveEvent); } else if (calendar.getEventClickListener() != null) { @@ -528,20 +534,47 @@ public class SimpleDayCell extends FocusableFlowPanel implements Date from = e.getStart(); Date to = e.getEnd(); - long duration = to.getTime() - from.getTime(); long daysMs = dayDiff * DateConstants.DAYINMILLIS; long weeksMs = weekDiff * DateConstants.WEEKINMILLIS; - from.setTime(startDateFrom.getTime() + weeksMs + daysMs); - to.setTime((from.getTime() + duration)); + + setDates(e, from, to, weeksMs + daysMs, false); e.setStart(from); e.setEnd(to); - e.setStartTime(new Date(from.getTime())); - e.setEndTime(new Date(to.getTime())); + if (w.isTimeSpecificEvent()) { + Date start = new Date(); + Date end = new Date(); + setDates(e, start, end, weeksMs + daysMs, true); + e.setStartTime(start); + e.setEndTime(end); + } else { + e.setStartTime(new Date(from.getTime())); + e.setEndTime(new Date(to.getTime())); + } updateDragPosition(w, dayDiff, weekDiff); } + private void setDates(CalendarEvent e, Date start, Date end, long shift, + boolean isDateTime) { + Date currentStart; + Date currentEnd; + if (isDateTime) { + currentStart = e.getStartTime(); + currentEnd = e.getEndTime(); + } else { + currentStart = e.getStart(); + currentEnd = e.getEnd(); + } + long duration = currentEnd.getTime() - currentStart.getTime(); + if (isDateTime) { + start.setTime(dndSourceStartDateTime.getTime() + shift); + } else { + start.setTime(dndSourceDateFrom.getTime() + shift); + } + end.setTime((start.getTime() + duration)); + } + private void eventMoved(CalendarEvent e) { calendar.updateEventToMonthGrid(e); if (calendar.getEventMovedListener() != null) { @@ -551,10 +584,6 @@ public class SimpleDayCell extends FocusableFlowPanel implements public void startCalendarEventDrag(MouseDownEvent event, final MonthEventLabel w) { - if (w.isTimeSpecificEvent()) { - return; - } - moveRegistration = addMouseMoveHandler(this); startX = event.getClientX(); startY = event.getClientY(); @@ -564,8 +593,11 @@ public class SimpleDayCell extends FocusableFlowPanel implements % getWidth(); CalendarEvent e = getEventByWidget(w); - startDateFrom = (Date) e.getStart().clone(); - startDateTo = (Date) e.getEnd().clone(); + dndSourceDateFrom = (Date) e.getStart().clone(); + dndSourceDateTo = (Date) e.getEnd().clone(); + + dndSourceStartDateTime = (Date) e.getStartTime().clone(); + dndSourceEndDateTime = (Date) e.getEndTime().clone(); Event.setCapture(getElement()); keyDownHandler = addKeyDownHandler(new KeyDownHandler() { @@ -591,8 +623,10 @@ public class SimpleDayCell extends FocusableFlowPanel implements moveEvent = getEventByWidget(w); } - moveEvent.setStart(startDateFrom); - moveEvent.setEnd(startDateTo); + moveEvent.setStart(dndSourceDateFrom); + moveEvent.setEnd(dndSourceDateTo); + moveEvent.setStartTime(dndSourceStartDateTime); + moveEvent.setEndTime(dndSourceEndDateTime); calendar.updateEventToMonthGrid(moveEvent); // reset drag-related properties diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index 0c09ae49c6..aace349392 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -152,7 +152,20 @@ public abstract class AbstractOrderedLayoutConnector extends public void onElementResize(ElementResizeEvent e) { updateLayoutHeight(); if (needsExpand()) { - getWidget().updateExpandCompensation(); + /* + * updateLayoutHeight causes calling of + * getLayoutManager().setNeedsMeasure(this) which informs this + * LayoutManager that the size of a component might have + * changed. Then a new layout phase is scheduled. So + * updateExpandCompensation must be delayed until layout phase + * will be completed. #12672 + */ + Scheduler.get().scheduleFinally(new ScheduledCommand() { + @Override + public void execute() { + getWidget().updateExpandCompensation(); + } + }); } } }; diff --git a/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java b/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java index 94961a6a50..d49581eaad 100644 --- a/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java +++ b/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java @@ -41,7 +41,7 @@ public class TabsheetConnector extends TabsheetBaseConnector implements final String key = getState().tabs.get(i).key; final boolean selected = key.equals(getState().selected); if (selected) { - getWidget().setActiveTabIndex(i); + getWidget().waitingForResponse = false; getWidget().selectTab(i); break; } diff --git a/client/tests/src/com/vaadin/client/LocatorUtilTest.java b/client/tests/src/com/vaadin/client/LocatorUtilTest.java new file mode 100644 index 0000000000..15536ac6fc --- /dev/null +++ b/client/tests/src/com/vaadin/client/LocatorUtilTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.vaadin.client.componentlocator.LocatorUtil; + +/* + * Test LocatorUtil.isUIElement() & isNotificaitonElement methods + */ +public class LocatorUtilTest extends TestCase { + + public void testIsUI1() { + boolean isUI = LocatorUtil.isUIElement("com.vaadin.ui.UI"); + Assert.assertTrue(isUI); + } + + public void testIsUI2() { + boolean isUI = LocatorUtil.isUIElement("/com.vaadin.ui.UI"); + Assert.assertTrue(isUI); + } + + public void testIsUI3() { + boolean isUI = LocatorUtil + .isUIElement("//com.vaadin.ui.UI[RandomString"); + Assert.assertTrue(isUI); + } + + public void testIsUI4() { + boolean isUI = LocatorUtil.isUIElement("//com.vaadin.ui.UI[0]"); + Assert.assertTrue(isUI); + } + + public void testIsNotification1() { + boolean isUI = LocatorUtil + .isNotificationElement("com.vaadin.ui.VNotification"); + Assert.assertTrue(isUI); + } + + public void testIsNotification2() { + boolean isUI = LocatorUtil + .isNotificationElement("com.vaadin.ui.Notification"); + Assert.assertTrue(isUI); + } + + public void testIsNotification3() { + boolean isUI = LocatorUtil + .isNotificationElement("/com.vaadin.ui.VNotification["); + Assert.assertTrue(isUI); + } + + public void testIsNotification4() { + boolean isUI = LocatorUtil + .isNotificationElement("//com.vaadin.ui.VNotification[0]"); + Assert.assertTrue(isUI); + } +} diff --git a/eclipse/Development Mode (vaadin).launch b/eclipse/Development Mode (vaadin).launch index 2b8ff23ce8..072b9a57c4 100644 --- a/eclipse/Development Mode (vaadin).launch +++ b/eclipse/Development Mode (vaadin).launch @@ -15,9 +15,9 @@ <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="3" projectName="vaadin" type="1"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=client%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=" javaProject="vaadin" path="3" type="4"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=shared%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=" javaProject="vaadin" path="3" type="4"/> "/> -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=uitest%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=%24%7Bworkspace_loc%3Avaadin%2Fbuild.properties%7D" javaProject="vaadin" path="3" type="4"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=push%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=" javaProject="vaadin" path="3" type="4"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=gwt%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=%24%7Bworkspace_loc%3Avaadin%2Fbuild.properties%7D" javaProject="vaadin" path="3" type="4"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=uitest%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=%24%7Bworkspace_loc%3Avaadin%2Fbuild.properties%7D" javaProject="vaadin" path="3" type="4"/> "/> </listAttribute> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> diff --git a/eclipse/Super Development Mode (vaadin).launch b/eclipse/Super Development Mode (vaadin).launch index ed243cba82..b57410bfd6 100644 --- a/eclipse/Super Development Mode (vaadin).launch +++ b/eclipse/Super Development Mode (vaadin).launch @@ -15,9 +15,9 @@ <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="3" projectName="vaadin" type="1"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=client%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=" javaProject="vaadin" path="3" type="4"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=shared%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=" javaProject="vaadin" path="3" type="4"/> "/> -<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=uitest%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=%24%7Bworkspace_loc%3Avaadin%2Fbuild.properties%7D" javaProject="vaadin" path="3" type="4"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=push%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=" javaProject="vaadin" path="3" type="4"/> "/> <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=gwt%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=%24%7Bworkspace_loc%3Avaadin%2Fbuild.properties%7D" javaProject="vaadin" path="3" type="4"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=uitest%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles=%24%7Bworkspace_loc%3Avaadin%2Fbuild.properties%7D" javaProject="vaadin" path="3" type="4"/> "/> </listAttribute> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.codeserver.CodeServer"/> diff --git a/push/build.xml b/push/build.xml index 9983886b7e..0a106f5023 100644 --- a/push/build.xml +++ b/push/build.xml @@ -16,7 +16,7 @@ <property name="vaadinPush.debug.js" location="${result.dir}/js/VAADIN/vaadinPush.debug.js" /> <!-- Keep the version number in sync with ivy.xml, server/src/com/vaadin/server/Constants.java --> - <property name="atmosphere.runtime.version" value="2.1.2.vaadin5" /> + <property name="atmosphere.runtime.version" value="2.1.2.vaadin6" /> <property name="jquery.js" location="lib/jquery/jquery-1.11.0.js" /> <path id="classpath.compile.custom" /> diff --git a/push/ivy.xml b/push/ivy.xml index 0d42103bce..fef53b4c9b 100644 --- a/push/ivy.xml +++ b/push/ivy.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ivy-module [ <!-- Keep the version number in sync with build.xml --> - <!ENTITY atmosphere.runtime.version "2.1.2.vaadin5"> + <!ENTITY atmosphere.runtime.version "2.1.2.vaadin6"> <!ENTITY atmosphere.js.version "2.1.5.vaadin4"> ]> diff --git a/server/build.xml b/server/build.xml index 9c85736b92..7bb70ffdc4 100644 --- a/server/build.xml +++ b/server/build.xml @@ -23,7 +23,7 @@ </union> <target name="jar"> - <property name="server.osgi.import" value="javax.servlet;version="2.4.0",javax.servlet.http;version="2.4.0",javax.validation;version="1.0.0.GA";resolution:=optional,org.jsoup;version="1.6.3",org.jsoup.parser;version="1.6.3",org.jsoup.nodes;version="1.6.3",org.jsoup.helper;version="1.6.3",org.jsoup.safety;version="1.6.3",org.json;version="0.0.20131108.vaadin1"" /> + <property name="server.osgi.import" value="javax.servlet;version="2.4.0",javax.servlet.http;version="2.4.0",javax.validation;version="1.0.0.GA";resolution:=optional,org.jsoup;version="1.6.3",org.jsoup.parser;version="1.6.3",org.jsoup.nodes;version="1.6.3",org.jsoup.helper;version="1.6.3",org.jsoup.safety;version="1.6.3",org.json;version="0.0.20080701"" /> <property name="server.osgi.require" value="com.vaadin.shared;bundle-version="${vaadin.version}",com.vaadin.push;bundle-version="${vaadin.version}";resolution:=optional,com.vaadin.sass-compiler;bundle-version="${vaadin.sass.version}";resolution:=optional" /> <antcall target="common.jar"> <param name="require-bundle" value="${server.osgi.require}" /> diff --git a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java index c5aab5a053..5a4e877554 100644 --- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java +++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java @@ -211,7 +211,8 @@ public class FieldGroup implements Serializable { public void setReadOnly(boolean fieldsReadOnly) { readOnly = fieldsReadOnly; for (Field<?> field : getFields()) { - if (!field.getPropertyDataSource().isReadOnly()) { + if (field.getPropertyDataSource() == null + || !field.getPropertyDataSource().isReadOnly()) { field.setReadOnly(fieldsReadOnly); } else { field.setReadOnly(true); @@ -244,15 +245,13 @@ public class FieldGroup implements Serializable { * @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 + * If the field is null or 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"); - } + throwIfFieldIsNull(field, propertyId); + throwIfPropertyIdAlreadyBound(field, propertyId); + fieldToPropertyId.put(field, propertyId); propertyIdToField.put(propertyId, field); if (itemDataSource == null) { @@ -264,6 +263,23 @@ public class FieldGroup implements Serializable { configureField(field); } + private void throwIfFieldIsNull(Field<?> field, Object propertyId) { + if (field == null) { + throw new BindException( + String.format( + "Cannot bind property id '%s' to a null field.", + propertyId)); + } + } + + private void throwIfPropertyIdAlreadyBound(Field<?> field, Object propertyId) { + if (propertyIdToField.containsKey(propertyId) + && propertyIdToField.get(propertyId) != field) { + throw new BindException("Property id " + propertyId + + " is already bound to another field"); + } + } + private <T> Property.Transactional<T> wrapInTransactionalProperty( Property<T> itemProperty) { return new TransactionalPropertyWrapper<T>(itemProperty); diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index fc0bf7381a..5841bfac4d 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -67,7 +67,7 @@ public interface Constants { // Keep the version number in sync with push/build.xml and other locations // listed in that file - static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "2.1.2.vaadin5"; + static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "2.1.2.vaadin6"; static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n" + "=================================================================\n" @@ -115,6 +115,15 @@ public interface Constants { + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING + ". Supported values are 'false','warning','true'"; + static final String CANNOT_ACQUIRE_CLASSLOADER_SEVERE = "\n" + + "=================================================================\n" + + "Vaadin was unable to acquire class loader from servlet container\n" + + "to load your application classes. Setup appropriate security\n" + + "policy to allow invoking Thread.getContextClassLoader() from\n" + + "VaadinService if you're not using custom class loader.\n" + + "NullPointerExceptions will be thrown later." + + "================================================================="; + static final String URL_PARAMETER_THEME = "theme"; static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode"; @@ -164,4 +173,5 @@ public interface Constants { static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; static final String PORTLET_CONTEXT = "PORTLET_CONTEXT"; + } diff --git a/server/src/com/vaadin/server/VaadinPortletService.java b/server/src/com/vaadin/server/VaadinPortletService.java index cff024672c..878b8964b6 100644 --- a/server/src/com/vaadin/server/VaadinPortletService.java +++ b/server/src/com/vaadin/server/VaadinPortletService.java @@ -46,16 +46,6 @@ public class VaadinPortletService extends VaadinService { throws ServiceException { super(deploymentConfiguration); this.portlet = portlet; - - // Set default class loader if not already set - if (getClassLoader() == null) { - /* - * The portlet is most likely to be loaded with a class loader - * specific to the application instead of some generic system class - * loader that loads the Vaadin classes. - */ - setClassLoader(portlet.getClass().getClassLoader()); - } } @Override @@ -162,7 +152,7 @@ public class VaadinPortletService extends VaadinService { if (Constants.PORTLET_CONTEXT.equals(staticFileLocation)) { return request.getContextPath(); - } else{ + } else { return trimTrailingSlashes(staticFileLocation); } } diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 4d8e7e9bc9..fb93a44d37 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -170,6 +170,10 @@ public abstract class VaadinService implements Serializable { + classLoaderName, e); } } + + if (getClassLoader() == null) { + setDefaultClassLoader(); + } } /** @@ -1861,4 +1865,25 @@ public abstract class VaadinService implements Serializable { eventRouter.fireEvent(new ServiceDestroyEvent(this)); } + /** + * Tries to acquire default class loader and sets it as a class loader for + * this {@link VaadinService} if found. If current security policy disallows + * acquiring class loader instance it will log a message and re-throw + * {@link SecurityException} + * + * @throws SecurityException + * If current security policy forbids acquiring class loader + * + * @since 7.3.5 + */ + protected void setDefaultClassLoader() { + try { + setClassLoader(VaadinServiceClassLoaderUtil + .findDefaultClassLoader()); + } catch (SecurityException e) { + getLogger().log(Level.SEVERE, + Constants.CANNOT_ACQUIRE_CLASSLOADER_SEVERE, e); + throw e; + } + } } diff --git a/server/src/com/vaadin/server/VaadinServiceClassLoaderUtil.java b/server/src/com/vaadin/server/VaadinServiceClassLoaderUtil.java new file mode 100644 index 0000000000..c9e73e2a29 --- /dev/null +++ b/server/src/com/vaadin/server/VaadinServiceClassLoaderUtil.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Utility class used by {@link VaadinService#setDefaultClassLoader()}. + * + * @since + * @author Vaadin Ltd + */ +class VaadinServiceClassLoaderUtil { + + private static class GetClassLoaderPrivilegedAction implements + PrivilegedAction<ClassLoader> { + @Override + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + } + + /** + * Called by {@link VaadinService#setDefaultClassLoader()} to acquire + * appropriate class loader to load application's classes (e.g. UI). Calls + * should be guarded by try/catch block to catch SecurityException and log + * appropriate message. The code for this method is modeled after + * recommendations laid out by JEE 5 specification sections EE.6.2.4.7 and + * EE.8.2.5 + * + * @return Instance of {@link ClassLoader} that should be used by this + * instance of {@link VaadinService} + * @throws SecurityException + * if current security policy doesn't allow acquiring current + * thread's context class loader + */ + static protected ClassLoader findDefaultClassLoader() + throws SecurityException { + return AccessController + .doPrivileged(new VaadinServiceClassLoaderUtil.GetClassLoaderPrivilegedAction()); + } + +} diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java index 8946ac4fae..6832da236a 100644 --- a/server/src/com/vaadin/server/VaadinServletService.java +++ b/server/src/com/vaadin/server/VaadinServletService.java @@ -51,16 +51,6 @@ public class VaadinServletService extends VaadinService { throws ServiceException { super(deploymentConfiguration); this.servlet = servlet; - - // Set default class loader if not already set - if (getClassLoader() == null) { - /* - * The servlet is most likely to be loaded with a class loader - * specific to the application instead of some generic system class - * loader that loads the Vaadin classes. - */ - setClassLoader(servlet.getClass().getClassLoader()); - } } private static boolean checkAtmosphereSupport() { diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java index cb5979d612..66018b02f2 100644 --- a/server/src/com/vaadin/server/WebBrowser.java +++ b/server/src/com/vaadin/server/WebBrowser.java @@ -295,6 +295,7 @@ public class WebBrowser implements Serializable { * * @return true if run on IPhone false if the user is not using IPhone or if * no information on the browser is present + * @since 7.3.3 */ public boolean isIPhone() { return browserDetails.isIPhone(); @@ -305,6 +306,7 @@ public class WebBrowser implements Serializable { * * @return true if run on IPad false if the user is not using IPad or if no * information on the browser is present + * @since 7.3.3 */ public boolean isIPad() { return browserDetails.isIPad(); diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index 22c6a76106..576cbd8411 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -216,7 +216,10 @@ public class FileUploadHandler implements RequestHandler { } } - private static final int LF = "\n".getBytes()[0]; + /** + * as per RFC 2045, line delimiters in headers are always CRLF, i.e. 13 10 + */ + private static final int LF = 10; private static final String CRLF = "\r\n"; @@ -295,6 +298,9 @@ public class FileUploadHandler implements RequestHandler { ByteArrayOutputStream bout = new ByteArrayOutputStream(); int readByte = stream.read(); while (readByte != LF) { + if (readByte == -1) { + throw new IOException("The multipart stream ended unexpectedly"); + } bout.write(readByte); readByte = stream.read(); } diff --git a/server/src/com/vaadin/ui/AbstractSelect.java b/server/src/com/vaadin/ui/AbstractSelect.java index b083db3183..2c4dd5be5d 100644 --- a/server/src/com/vaadin/ui/AbstractSelect.java +++ b/server/src/com/vaadin/ui/AbstractSelect.java @@ -1675,6 +1675,8 @@ public abstract class AbstractSelect extends AbstractField<Object> implements // Clears the item id mapping table itemIdMapper.removeAll(); + adjustSelection(); + // Notify all listeners fireItemSetChange(); } @@ -1713,6 +1715,23 @@ public abstract class AbstractSelect extends AbstractField<Object> implements } /** + * Removes orphaned ids from selection. + */ + protected void adjustSelection() { + Object value = getValue(); + if (isMultiSelect() && (value instanceof Collection)) { + Collection<?> collection = (Collection<?>) value; + for (Object id : collection) { + if (!containsId(id)) { + unselect(id); + } + } + } else if (!containsId(value)) { + unselect(value); + } + } + + /** * Implementation of item set change event. */ private static class ItemSetChangeEvent extends EventObject implements diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java index 63ac9fe35c..72ff6eb0e0 100644 --- a/server/src/com/vaadin/ui/Calendar.java +++ b/server/src/com/vaadin/ui/Calendar.java @@ -516,7 +516,8 @@ public class Calendar extends AbstractComponent implements day.date = df_date.format(date); day.localizedDateFormat = weeklyCaptionFormatter.format(date); day.dayOfWeek = getDowByLocale(currentCalendar); - day.week = currentCalendar.get(java.util.Calendar.WEEK_OF_YEAR); + day.week = getWeek(currentCalendar); + day.yearOfWeek = getYearOfWeek(currentCalendar); days.add(day); @@ -560,6 +561,23 @@ public class Calendar extends AbstractComponent implements state.actions = createActionsList(actionMap); } + private int getWeek(java.util.Calendar calendar) { + return calendar.get(java.util.Calendar.WEEK_OF_YEAR); + } + + private int getYearOfWeek(java.util.Calendar calendar) { + // Would use calendar.getWeekYear() but it's only available since 1.7. + int week = getWeek(calendar); + int month = calendar.get(java.util.Calendar.MONTH); + int year = calendar.get(java.util.Calendar.YEAR); + + if (week == 1 && month == java.util.Calendar.DECEMBER) { + return year + 1; + } + + return year; + } + private void setActionsForEachHalfHour( Map<CalendarDateRange, Set<Action>> actionMap, Date start, Date end, Action.Handler actionHandler) { @@ -1772,7 +1790,7 @@ public class Calendar extends AbstractComponent implements String[] splitted = event.split("w"); if (splitted.length == 2) { try { - int yr = 1900 + Integer.parseInt(splitted[0]); + int yr = Integer.parseInt(splitted[0]); int week = Integer.parseInt(splitted[1]); fireWeekClick(week, yr); } catch (NumberFormatException e) { diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index 34d48a9b18..9da25d3e48 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -1029,7 +1029,7 @@ public class Table extends AbstractSelect implements Action.Container, * </p> * * <p> - * If Table has width set ({@link #setWidth(float, int)} ) the client side + * If Table has height set ({@link #setHeight(float, int)} ) the client side * may update the page length automatically the correct value. * </p> * diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 438b086ec2..78cb5488e8 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -499,6 +499,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements private void attachWindow(Window w) { windows.add(w); w.setParent(this); + fireComponentAttachEvent(w); markAsDirty(); } @@ -523,6 +524,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements window.setParent(null); markAsDirty(); window.fireClose(); + fireComponentDetachEvent(window); return true; } diff --git a/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java index 8dff224627..fcaabcc079 100644 --- a/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java +++ b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java @@ -442,6 +442,8 @@ public class ContainerEventProvider implements CalendarEditableEventProvider, /** * Set the all day property for the event + * + * @since 7.3.4 */ public void setAllDayProperty(Object allDayProperty) { this.allDayProperty = allDayProperty; @@ -449,6 +451,8 @@ public class ContainerEventProvider implements CalendarEditableEventProvider, /** * Get the all day property for the event + * + * @since 7.3.4 */ public Object getAllDayProperty() { return allDayProperty; diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java index f4d47f89d4..0e99b26856 100644 --- a/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java @@ -47,6 +47,7 @@ public class BasicBackwardHandler implements BackwardHandler { // calculate amount to move back int durationInDays = (int) (((end.getTime()) - start.getTime()) / DateConstants.DAYINMILLIS); durationInDays++; + // for week view durationInDays = -7, for day view durationInDays = -1 durationInDays = -durationInDays; // set new start and end times @@ -59,6 +60,21 @@ public class BasicBackwardHandler implements BackwardHandler { javaCalendar.add(java.util.Calendar.DATE, durationInDays); Date newEnd = javaCalendar.getTime(); + if (start.equals(end)) { // day view + int firstDay = event.getComponent().getFirstVisibleDayOfWeek(); + int lastDay = event.getComponent().getLastVisibleDayOfWeek(); + int dayOfWeek = javaCalendar.get(Calendar.DAY_OF_WEEK); + + // we suppose that 7 >= lastDay >= firstDay >= 1 + while (!(firstDay <= dayOfWeek && dayOfWeek <= lastDay)) { + javaCalendar.add(java.util.Calendar.DATE, -1); + dayOfWeek = javaCalendar.get(Calendar.DAY_OF_WEEK); + } + + newStart = javaCalendar.getTime(); + newEnd = javaCalendar.getTime(); + } + setDates(event, newStart, newEnd); } diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java index 96c3c097dc..45b44cb673 100644 --- a/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java @@ -45,6 +45,7 @@ public class BasicForwardHandler implements ForwardHandler { // calculate amount to move forward int durationInDays = (int) (((end.getTime()) - start.getTime()) / DateConstants.DAYINMILLIS); + // for week view durationInDays = 7, for day view durationInDays = 1 durationInDays++; // set new start and end times @@ -57,6 +58,21 @@ public class BasicForwardHandler implements ForwardHandler { javaCalendar.add(java.util.Calendar.DATE, durationInDays); Date newEnd = javaCalendar.getTime(); + if (start.equals(end)) { // day view + int firstDay = event.getComponent().getFirstVisibleDayOfWeek(); + int lastDay = event.getComponent().getLastVisibleDayOfWeek(); + int dayOfWeek = javaCalendar.get(Calendar.DAY_OF_WEEK); + + // we suppose that 7 >= lastDay >= firstDay >= 1 + while (!(firstDay <= dayOfWeek && dayOfWeek <= lastDay)) { + javaCalendar.add(java.util.Calendar.DATE, 1); + dayOfWeek = javaCalendar.get(Calendar.DAY_OF_WEEK); + } + + newStart = javaCalendar.getTime(); + newEnd = javaCalendar.getTime(); + } + setDates(event, newStart, newEnd); } diff --git a/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupTests.java b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupTests.java new file mode 100644 index 0000000000..eb8f21c839 --- /dev/null +++ b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupTests.java @@ -0,0 +1,40 @@ +package com.vaadin.data.fieldgroup; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.mock; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.ui.Field; + +public class FieldGroupTests { + + private FieldGroup sut; + private Field field; + + @Before + public void setup() { + sut = new FieldGroup(); + field = mock(Field.class); + } + + @Test + public void fieldIsBound() { + sut.bind(field, "foobar"); + + assertThat(sut.getField("foobar"), is(field)); + } + + @Test(expected = FieldGroup.BindException.class) + public void cannotBindToAlreadyBoundProperty() { + sut.bind(field, "foobar"); + sut.bind(mock(Field.class), "foobar"); + } + + @Test(expected = FieldGroup.BindException.class) + public void cannotBindNullField() { + sut.bind(null, "foobar"); + } +} diff --git a/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java new file mode 100644 index 0000000000..2cb4c3bf4d --- /dev/null +++ b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server.communication; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import com.vaadin.server.VaadinRequest; + +/** + * Tests whether we get infinite loop if InputStream is already read (#10096) + */ +public class FileUploadHandlerTest { + + private FileUploadHandler handler; + private VaadinRequest request; + + @Before + public void setup() throws Exception { + handler = new FileUploadHandler(); + InputStream inputStream = new InputStream() { + private int counter = 0; + + @Override + public int read() throws IOException { + counter++; + if (counter > 6) { + throw new RuntimeException( + "-1 is ignored by FileUploadHandler"); + } + return -1; + } + + }; + request = Mockito.mock(VaadinRequest.class); + Mockito.when(request.getInputStream()).thenReturn(inputStream); + Mockito.when(request.getHeader("Content-Length")).thenReturn("211"); + } + + @Test(expected = IOException.class) + public void testStreamEnded() throws IOException { + handler.doHandleSimpleMultipartFileUpload(null, request, null, null, + null, null, null); + + } + +} diff --git a/server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java b/server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java index 214341371a..b127ffe7e5 100644 --- a/server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java +++ b/server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java @@ -19,6 +19,7 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.easymock.EasyMock; @@ -26,6 +27,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.vaadin.server.MockServletConfig; import com.vaadin.server.ServiceException; import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinServlet; @@ -36,6 +38,7 @@ import com.vaadin.server.communication.ServerRpcHandler.RpcRequest; import com.vaadin.shared.ApplicationConstants; import com.vaadin.tests.util.AlwaysLockedVaadinSession; import com.vaadin.tests.util.MockDeploymentConfiguration; + import elemental.json.JsonException; /** @@ -62,10 +65,12 @@ public class CsrfTokenMissingTestServer { /** * Initialize the mock servlet and other stuff for our tests. + * */ @Before - public void initMockStuff() throws ServiceException { + public void initMockStuff() throws ServiceException, ServletException { mockServlet = new VaadinServlet(); + mockServlet.init(new MockServletConfig()); mockDeploymentConfiguration = new MockDeploymentConfiguration(); mockService = new VaadinServletService(mockServlet, diff --git a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java index 1220209479..83269ede28 100644 --- a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java +++ b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java @@ -48,6 +48,8 @@ public class TestClassesSerializable extends TestCase { "com\\.vaadin\\.server\\.MockServletConfig", // "com\\.vaadin\\.server\\.MockServletContext", // "com\\.vaadin\\.server\\.Constants", // + "com\\.vaadin\\.server\\.VaadinServiceClassLoaderUtil", // + "com\\.vaadin\\.server\\.VaadinServiceClassLoaderUtil\\$GetClassLoaderPrivilegedAction", // "com\\.vaadin\\.server\\.communication\\.FileUploadHandler\\$SimpleMultiPartInputStream", // "com\\.vaadin\\.server\\.communication\\.PushRequestHandler.*", "com\\.vaadin\\.server\\.communication\\.PushHandler.*", // PushHandler diff --git a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java index fcc54a989d..b2faca1ed6 100644 --- a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java +++ b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java @@ -80,11 +80,11 @@ public class TestStreamVariableMapping extends TestCase { private LegacyCommunicationManager createCommunicationManager() throws Exception { VaadinServlet servlet = new VaadinServlet(); + servlet.init(new MockServletConfig()); VaadinServletService vss = new VaadinServletService(servlet, new MockDeploymentConfiguration()); servlet.init(new MockServletConfig()); return new LegacyCommunicationManager( new AlwaysLockedVaadinSession(vss)); } - } diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractselect/TestAbstractSelectValueUpdate.java b/server/tests/src/com/vaadin/tests/server/component/abstractselect/TestAbstractSelectValueUpdate.java new file mode 100644 index 0000000000..e81f6e09b6 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/abstractselect/TestAbstractSelectValueUpdate.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server.component.abstractselect; + +import java.util.Collection; +import java.util.Collections; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.ui.AbstractSelect; + +public class TestAbstractSelectValueUpdate { + + @Test + public void removeItem_deleteItemFromUnderlyingContainer_selectValueIsUpdated() { + BeanItemContainer<Object> container = new BeanItemContainer<Object>( + Object.class); + Object item1 = new Object(); + Object item2 = new Object(); + container.addBean(item1); + container.addBean(item2); + TestSelect select = new TestSelect(); + select.setContainerDataSource(container); + + select.setValue(item1); + + Assert.assertNotNull("Value is null after selection", select.getValue()); + + container.removeItem(item1); + + Assert.assertNull("Value is not null after removal", select.getValue()); + } + + @Test + public void removeItem_multiselectSectionDeleteItemFromUnderlyingContainer_selectValueIsUpdated() { + BeanItemContainer<Object> container = new BeanItemContainer<Object>( + Object.class); + Object item1 = new Object(); + Object item2 = new Object(); + container.addBean(item1); + container.addBean(item2); + TestSelect select = new TestSelect(); + select.setMultiSelect(true); + select.setContainerDataSource(container); + + select.setValue(Collections.singletonList(item1)); + + checkSelectedItemsCount(select, 1); + + container.removeItem(item1); + + checkSelectedItemsCount(select, 0); + } + + private void checkSelectedItemsCount(TestSelect select, int count) { + Assert.assertNotNull("Selected value is null", select.getValue()); + Assert.assertTrue("Selected value is not a collection", + select.getValue() instanceof Collection); + Assert.assertEquals("Wrong number of selected items", + ((Collection<?>) select.getValue()).size(), count); + } + + private class TestSelect extends AbstractSelect { + + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/FieldGroupTest.java b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/FieldGroupTest.java new file mode 100644 index 0000000000..da86c83771 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/FieldGroupTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server.component.fieldgroup; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.data.fieldgroup.FieldGroup; +import com.vaadin.ui.TextField; + +/** + * + * Tests for {@link FieldGroup}. + * + * @author Vaadin Ltd + */ +public class FieldGroupTest { + + @Test + public void setReadOnly_readOnlyAndNoDataSource_fieldIsReadOnly() { + FieldGroup fieldGroup = new FieldGroup(); + + TextField field = new TextField(); + fieldGroup.bind(field, "property"); + + fieldGroup.setReadOnly(true); + + Assert.assertTrue("Field is not read only", field.isReadOnly()); + } + + @Test + public void setReadOnly_writableAndNoDataSource_fieldIsWritable() { + FieldGroup fieldGroup = new FieldGroup(); + + TextField field = new TextField(); + fieldGroup.bind(field, "property"); + + fieldGroup.setReadOnly(false); + + Assert.assertFalse("Field is not writable", field.isReadOnly()); + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java b/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java index 51d396801d..5720744e2f 100644 --- a/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java +++ b/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java @@ -3,12 +3,17 @@ package com.vaadin.tests.server.component.window; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import org.junit.Assert; import org.junit.Test; import com.vaadin.server.ClientConnector; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinSession; import com.vaadin.tests.util.AlwaysLockedVaadinSession; +import com.vaadin.ui.HasComponents.ComponentAttachEvent; +import com.vaadin.ui.HasComponents.ComponentAttachListener; +import com.vaadin.ui.HasComponents.ComponentDetachEvent; +import com.vaadin.ui.HasComponents.ComponentDetachListener; import com.vaadin.ui.Label; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; @@ -213,6 +218,45 @@ public class AttachDetachWindow { assertDetached(sub); } + @Test + public void addWindow_attachEventIsFired() { + TestUI ui = new TestUI(); + final Window window = new Window(); + + final boolean[] eventFired = new boolean[1]; + ui.addComponentAttachListener(new ComponentAttachListener() { + + @Override + public void componentAttachedToContainer(ComponentAttachEvent event) { + eventFired[0] = event.getAttachedComponent().equals(window); + } + }); + ui.addWindow(window); + Assert.assertTrue("Attach event is not fired for added window", + eventFired[0]); + } + + @Test + public void removeWindow_detachEventIsFired() { + TestUI ui = new TestUI(); + final Window window = new Window(); + + final boolean[] eventFired = new boolean[1]; + ui.addComponentDetachListener(new ComponentDetachListener() { + + @Override + public void componentDetachedFromContainer( + ComponentDetachEvent event) { + eventFired[0] = event.getDetachedComponent().equals(window); + } + }); + ui.addWindow(window); + ui.removeWindow(window); + + Assert.assertTrue("Detach event is not fired for removed window", + eventFired[0]); + } + /** * Asserts that win and its children are attached to testApp and their * attach() methods have been called. diff --git a/shared/build.xml b/shared/build.xml index 197f63c027..1e7e788be5 100644 --- a/shared/build.xml +++ b/shared/build.xml @@ -18,7 +18,7 @@ <path id="classpath.test.custom" /> <target name="jar"> - <property name="shared.osgi.import" value="org.json;version="0.0.20131108.vaadin1", com.google.gwt.thirdparty.guava.common.annotations;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.base;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.base.internal;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.cache;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.collect;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.eventbus;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.io;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.net;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.primitives;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.util.concurrent;version="16.0.1.vaadin1", com.google.gwt.thirdparty.streamhtmlparser;version="0.0.10.vaadin1", com.google.gwt.thirdparty.streamhtmlparser.impl;version="0.0.10.vaadin1", com.google.gwt.thirdparty.streamhtmlparser.util;version="0.0.10.vaadin1", org.w3c.flute.parser;version="1.3.0.gg2", org.w3c.flute.parser.selectors;version="1.3.0.gg2", org.w3c.flute.util;version="1.3.0.gg2"" /> + <property name="shared.osgi.import" value="org.json;version="0.0.20080701", com.google.gwt.thirdparty.guava.common.annotations;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.base;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.base.internal;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.cache;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.collect;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.eventbus;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.io;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.net;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.primitives;version="16.0.1.vaadin1", com.google.gwt.thirdparty.guava.common.util.concurrent;version="16.0.1.vaadin1", com.google.gwt.thirdparty.streamhtmlparser;version="0.0.10.vaadin1", com.google.gwt.thirdparty.streamhtmlparser.impl;version="0.0.10.vaadin1", com.google.gwt.thirdparty.streamhtmlparser.util;version="0.0.10.vaadin1", org.w3c.flute.parser;version="1.3.0.gg2", org.w3c.flute.parser.selectors;version="1.3.0.gg2", org.w3c.flute.util;version="1.3.0.gg2"" /> <delete dir="${src.filtered}" /> <!-- Update version in Version.java --> <copy todir="${src.filtered}"> diff --git a/shared/src/com/vaadin/shared/VBrowserDetails.java b/shared/src/com/vaadin/shared/VBrowserDetails.java index a85d031c49..fa21bddc96 100644 --- a/shared/src/com/vaadin/shared/VBrowserDetails.java +++ b/shared/src/com/vaadin/shared/VBrowserDetails.java @@ -479,7 +479,8 @@ public class VBrowserDetails implements Serializable { /** * Tests if the browser is run on iPhone. * - * @return + * @return true if run on iPhone, false otherwise + * @since 7.3.3 */ public boolean isIPhone() { return isIPhone; @@ -488,7 +489,8 @@ public class VBrowserDetails implements Serializable { /** * Tests if the browser is run on iPad. * - * @return + * @return true if run on iPad, false otherwise + * @since 7.3.3 */ public boolean isIPad() { return isIPad; diff --git a/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java b/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java index de48f1a06a..93bd05bc1e 100644 --- a/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java +++ b/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java @@ -44,6 +44,7 @@ public class CalendarState extends AbstractComponentState { public String localizedDateFormat; public int dayOfWeek; public int week; + public int yearOfWeek; } public static class Action implements java.io.Serializable { diff --git a/uitest/ivy.xml b/uitest/ivy.xml index 9af209662c..14c8bc6ce3 100644 --- a/uitest/ivy.xml +++ b/uitest/ivy.xml @@ -107,6 +107,9 @@ <dependency org="com.vaadin" name="vaadin-buildhelpers" rev="${vaadin.version}" conf="compile-theme->build" /> + <dependency org="org.eclipse.jgit" name="org.eclipse.jgit" + rev="3.5.1.201410131835-r" conf="ide,build->default" /> + </dependencies> </ivy-module> diff --git a/uitest/src/com/vaadin/tests/applicationservlet/SessionExpiration.java b/uitest/src/com/vaadin/tests/applicationservlet/SessionExpiration.java index 8fc6d56161..206e763497 100644 --- a/uitest/src/com/vaadin/tests/applicationservlet/SessionExpiration.java +++ b/uitest/src/com/vaadin/tests/applicationservlet/SessionExpiration.java @@ -17,7 +17,6 @@ package com.vaadin.tests.applicationservlet; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUIWithLog; -import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; @@ -26,15 +25,13 @@ public class SessionExpiration extends AbstractTestUIWithLog { @Override protected void setup(VaadinRequest request) { getSession().getSession().setMaxInactiveInterval(2); - Button b = new Button("Click to avoid expiration"); - b.addClickListener(new ClickListener() { + addButton("Click to avoid expiration", new ClickListener() { @Override public void buttonClick(ClickEvent event) { log("Clicked"); } }); - addComponent(b); } @Override diff --git a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java index 558379260b..3a7d42e29c 100644 --- a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java +++ b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java @@ -10,6 +10,7 @@ import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.shared.ui.ui.Transport; import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; +import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.Notification; @@ -181,6 +182,12 @@ public abstract class AbstractTestUI extends UI { getLayout().replaceComponent(oldComponent, newComponent); } + protected void addButton(String caption, Button.ClickListener listener) { + Button button = new Button(caption); + button.addClickListener(listener); + addComponent(button); + } + protected String getTestDescription() { return null; }; diff --git a/uitest/src/com/vaadin/tests/components/accordion/AccordionRemoveTab.java b/uitest/src/com/vaadin/tests/components/accordion/AccordionRemoveTab.java index 86e718596e..af54e15b5a 100644 --- a/uitest/src/com/vaadin/tests/components/accordion/AccordionRemoveTab.java +++ b/uitest/src/com/vaadin/tests/components/accordion/AccordionRemoveTab.java @@ -53,16 +53,13 @@ public class AccordionRemoveTab extends AbstractTestUI { Tab last = tabs.addTab(l); last.setCaption("Three"); - Button remove = new Button("Remove First"); - remove.addClickListener(new Button.ClickListener() { + addButton("Remove First", new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { tabs.removeComponent(tabs.iterator().next()); } }); - - addComponent(remove); } @Override diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarBackwardForward.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarBackwardForward.java new file mode 100644 index 0000000000..5a21353d7d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarBackwardForward.java @@ -0,0 +1,132 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.calendar; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Locale; + +import com.vaadin.annotations.Theme; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Calendar; +import com.vaadin.ui.Calendar.TimeFormat; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler; +import com.vaadin.ui.components.calendar.event.BasicEvent; + +/** + * Test: Vaadin Calendar: Navigation to invisible days of week (#12243) + * + * @author Vaadin Ltd + */ +@Theme("tests-calendar") +public class CalendarBackwardForward extends AbstractTestUI { + + private static final long serialVersionUID = 1L; + private Calendar calendar; + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + calendar = new Calendar(); + + try { + + BasicEvent event = new BasicEvent("EVENT NAME 1", + "EVENT TOOLTIP 1", + new SimpleDateFormat("yyyy-MM-dd HH:mm") + .parse("2013-09-05 15:30"), new SimpleDateFormat( + "yyyy-MM-dd HH:mm").parse("2013-09-07 22:20")); + event.setStyleName("color1"); + calendar.addEvent(event); + + event = new BasicEvent("EVENT NAME 2", "EVENT TOOLTIP 2", + new SimpleDateFormat("yyyy-MM-dd HH:mm") + .parse("2013-09-05 12:10"), new SimpleDateFormat( + "yyyy-MM-dd HH:mm").parse("2013-09-05 13:20")); + event.setStyleName("color2"); + calendar.addEvent(event); + + event = new BasicEvent("EVENT NAME 3", "EVENT TOOLTIP 3", + new SimpleDateFormat("yyyy-MM-dd HH:mm") + .parse("2013-09-01 11:30"), new SimpleDateFormat( + "yyyy-MM-dd HH:mm").parse("2013-09-29 15:20")); + event.setStyleName("color3"); + calendar.addEvent(event); + + event = new BasicEvent("EVENT NAME 4", "EVENT TOOLTIP 4", + new SimpleDateFormat("yyyy-MM-dd HH:mm") + .parse("2013-09-01 11:30"), new SimpleDateFormat( + "yyyy-MM-dd HH:mm").parse("2013-09-01 15:20")); + event.setStyleName("color4"); + event.setAllDay(true); + calendar.addEvent(event); + } catch (ParseException e1) { // Nothing to do + e1.printStackTrace(); + } + + try { + calendar.setStartDate(new SimpleDateFormat("yyyy-MM-dd") + .parse("2013-09-01")); + calendar.setEndDate(new SimpleDateFormat("yyyy-MM-dd") + .parse("2013-09-30")); + } catch (ParseException e) { // Nothing to do + + } + + calendar.setImmediate(true); + + // in english locale first day of week - sunday + calendar.setLocale(Locale.ENGLISH); + // show only working days: 2 - monday, 6 - friday + calendar.setFirstVisibleDayOfWeek(2); + calendar.setLastVisibleDayOfWeek(6); + + calendar.setTimeFormat(TimeFormat.Format24H); + calendar.setHandler((EventResizeHandler) null); + setEnabled(true); + + addComponent(calendar); + calendar.setSizeFull(); + setSizeFull(); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "If one uses the feature setVisibleDaysOfWeek of Calendar, the invisible days should be skipped in single-day-mode."; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 12243; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarBackwardForwardTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarBackwardForwardTest.java new file mode 100644 index 0000000000..98773f475b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarBackwardForwardTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.calendar; + +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.IOException; +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests: Vaadin Calendar: Navigation to invisible days of week (#12243) + * + * @author Vaadin Ltd + */ +public class CalendarBackwardForwardTest extends MultiBrowserTest { + + @Test + public void testCalendar() throws InterruptedException, IOException { + openTestURL(); + + openWeekView(); + openDayView(); + clickCalendarNext(); + + WebElement headerDayElement = getDriver().findElement( + By.className("v-calendar-header-day")); + + assertThat("This day should be Monday 9/9/13", headerDayElement + .getText().equals("Monday 9/9/13")); + + for (int i = 0; i < 6; i++) { + clickCalendarBack(); + } + + headerDayElement = getDriver().findElement( + By.className("v-calendar-header-day")); + + assertThat("This day should be Friday 8/30/13", headerDayElement + .getText().equals("Friday 8/30/13")); + } + + private void openWeekView() { + List<WebElement> elements = getDriver().findElements( + By.className("v-calendar-week-number")); + + for (WebElement webElement : elements) { + if (webElement.getText().equals("36")) { + webElement.click(); + break; + } + } + } + + private void openDayView() { + List<WebElement> elements = getDriver().findElements( + By.className("v-calendar-header-day")); + + for (WebElement webElement : elements) { + if (webElement.getText().contains("Friday 9/6/13")) { + webElement.click(); + break; + } + } + } + + private void clickCalendarNext() { + List<WebElement> elements = getDriver().findElements( + By.className("v-calendar-next")); + + elements.get(0).click(); + } + + private void clickCalendarBack() { + List<WebElement> elements = getDriver().findElements( + By.className("v-calendar-back")); + + elements.get(0).click(); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthViewDndEvent.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthViewDndEvent.java new file mode 100644 index 0000000000..b36b4d200e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthViewDndEvent.java @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.calendar; + +import java.util.Date; +import java.util.List; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Calendar; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.components.calendar.event.BasicEvent; +import com.vaadin.ui.components.calendar.event.BasicEventProvider; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider.EventSetChangeEvent; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider.EventSetChangeListener; + +/** + * Test UI for DnD regular (not all day event) in month view. + * + * @author Vaadin Ltd + */ +public class CalendarMonthViewDndEvent extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final Calendar calendar = new Calendar("Test calendar"); + final java.util.Calendar cal = getAdjustedCalendar(); + + Date from = cal.getTime(); + + Date start = new Date(from.getTime() - 24 * 3600000); + calendar.setStartDate(start); + + cal.add(java.util.Calendar.HOUR, 1); + Date to = cal.getTime(); + + cal.add(java.util.Calendar.MONTH, 1); + calendar.setEndDate(cal.getTime()); + + final BasicEvent basicEvent = new BasicEvent("event", "description", + from, to); + + HorizontalLayout info = new HorizontalLayout(); + info.setSpacing(true); + info.setMargin(true); + addComponent(info); + final Label startLbl = new Label(String.valueOf(from.getTime())); + startLbl.addStyleName("start"); + info.addComponent(startLbl); + + final Label endLbl = new Label(String.valueOf(to.getTime())); + endLbl.addStyleName("end"); + info.addComponent(endLbl); + + BasicEventProvider provider = new BasicEventProvider(); + provider.addEvent(basicEvent); + calendar.setEventProvider(provider); + provider.addEventSetChangeListener(new EventSetChangeListener() { + + @Override + public void eventSetChange(EventSetChangeEvent event) { + List<CalendarEvent> events = event.getProvider().getEvents( + new Date(0), new Date(Long.MAX_VALUE)); + CalendarEvent calEvent = events.get(0); + Date startEvent = calEvent.getStart(); + Date endEvent = calEvent.getEnd(); + + startLbl.setValue(String.valueOf(startEvent.getTime())); + endLbl.setValue(String.valueOf(endEvent.getTime())); + } + }); + + addComponent(calendar); + } + + @Override + protected String getTestDescription() { + return "Allow DnD any events in Calendar Month view"; + } + + @Override + protected Integer getTicketNumber() { + return 12413; + } + + private java.util.Calendar getAdjustedCalendar() { + final java.util.Calendar cal = java.util.Calendar.getInstance(); + + cal.set(java.util.Calendar.SECOND, 0); + cal.set(java.util.Calendar.MILLISECOND, 0); + return cal; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthViewDndEventTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthViewDndEventTest.java new file mode 100644 index 0000000000..3248804eed --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthViewDndEventTest.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.calendar; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.DndActionsTest; + +/** + * Test to check how DnD works for regular (not all day event) in calendar month + * view. + * + * @author Vaadin Ltd + */ +public class CalendarMonthViewDndEventTest extends DndActionsTest { + + @Test + public void dragAndDropEventToNextDay() { + openTestURL(); + + WebElement calendar = findElement(By.className("v-calendar")); + int calendarRight = calendar.getLocation().getX() + + calendar.getSize().getWidth(); + + WebElement event = findElement(By.className("v-calendar-event")); + int x = event.getLocation().getX(); + int width = event.getSize().getWidth(); + + // does calendar have space on the right for one more event (i.e. day + // cell on the right). + boolean moveRight = event.getLocation().getX() + 2 + * event.getSize().getWidth() <= calendarRight; + + WebElement cell = getParentCell(event, "v-calendar-month-day"); + + int cellY = cell.getLocation().getY(); + int cellHeight = cell.getSize().getHeight(); + + long origStart = getTime("start"); + long origEnd = getTime("end"); + + if (moveRight) { + dragAndDrop(event, event.getSize().getWidth() + 5, 0); + } else { + dragAndDrop(event, -width / 2, 0); + } + + event = findElement(By.className("v-calendar-event")); + int newX = event.getLocation().getX(); + int newY = event.getLocation().getY(); + + Assert.assertTrue( + "Moved event has wrong Y position (not the same row), new Y position=" + + newY + ", cell Y position=" + cellY + + ", cell height=" + cellHeight, newY >= cellY + && newY < cellY + cellHeight); + if (moveRight) { + Assert.assertTrue( + "Moved event has wrong X position (not after original event)", + newX >= x + width - 1); + } else { + width = event.getSize().getWidth(); + Assert.assertTrue( + "Moved event has wrong X position (not after original event)", + x >= newX + width - 1); + } + + long start = getTime("start"); + long end = getTime("end"); + + int day = 24 * 3600000; + if (moveRight) { + Assert.assertEquals( + "Start date of moved event is not next day, same time", + origStart + day, start); + Assert.assertEquals( + "End date of moved event is not next day, same time", + origEnd + day, end); + } else { + Assert.assertEquals( + "Start date of moved event is not previous day, same time", + origStart - day, start); + Assert.assertEquals( + "End date of moved event is not previous day, same time", + origEnd - day, end); + + } + } + + private WebElement getParentCell(WebElement element, String style) { + WebElement parent = element; + do { + // ".." xpath expression chooses the parent of the element + parent = parent.findElement(By.xpath("..")); + } while (!parent.getAttribute("class").contains(style)); + return parent; + } + + private long getTime(String style) { + WebElement start = findElement(By.className(style)); + return Long.parseLong(start.getText()); + } +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarWeekSelection.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarWeekSelection.java new file mode 100644 index 0000000000..c74f2a53e3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarWeekSelection.java @@ -0,0 +1,39 @@ +package com.vaadin.tests.components.calendar; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Locale; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Calendar; + +public class CalendarWeekSelection extends AbstractTestUI { + @Override + protected void setup(VaadinRequest request) { + Calendar calendar = new Calendar(); + calendar.setLocale(Locale.US); + + try { + calendar.setStartDate(new SimpleDateFormat("yyyy-MM-dd") + .parse("2013-12-15")); + calendar.setEndDate(new SimpleDateFormat("yyyy-MM-dd") + .parse("2014-01-15")); + } catch (ParseException e) { + e.printStackTrace(); + } + + addComponent(calendar); + } + + @Override + protected Integer getTicketNumber() { + return 14783; + } + + @Override + protected String getTestDescription() { + return "December 2013 - January 2014. Clicking the week 1 " + + "should open the week view for the first week of 2014."; + } +} diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarWeekSelectionTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarWeekSelectionTest.java new file mode 100644 index 0000000000..83f41994ae --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarWeekSelectionTest.java @@ -0,0 +1,41 @@ +package com.vaadin.tests.components.calendar; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class CalendarWeekSelectionTest extends MultiBrowserTest { + + @Test + public void correctYearIsSelected() { + openTestURL(); + + clickOnWeek("1"); + + assertThat(getFirstDayOfTheYear().getText(), is("Wednesday 1/1/14")); + } + + private WebElement getFirstDayOfTheYear() { + WebElement header = findElement(By.className("v-calendar-header-week")); + List<WebElement> headerElements = header.findElements(By.tagName("td")); + + // Wednesday is the first day of 2014. + return headerElements.get(4); + } + + private void clickOnWeek(String week) { + for (WebElement e : findElements(By.className("v-calendar-week-number"))) { + if (e.getText().equals(week)) { + e.click(); + break; + } + } + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldIsValid.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldIsValid.java index d3f30f3b37..66d1c34ab7 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DateFieldIsValid.java +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldIsValid.java @@ -7,7 +7,6 @@ import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUIWithLog; -import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.DateField; @@ -42,8 +41,7 @@ public class DateFieldIsValid extends AbstractTestUIWithLog { } }); addComponent(dateField); - Button button = new Button("check dateField"); - button.addClickListener(new ClickListener() { + addButton("check dateField", new ClickListener() { @Override public void buttonClick(ClickEvent event) { @@ -51,7 +49,6 @@ public class DateFieldIsValid extends AbstractTestUIWithLog { + ", is valid: " + dateField.isValid()); } }); - addComponent(button); } /** diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldPopupClosing.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldPopupClosing.java new file mode 100644 index 0000000000..60508a30d4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldPopupClosing.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.datefield; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.DateField; + +public class DateFieldPopupClosing extends AbstractTestUI { + + static final String DATEFIELD_ID = "datefield"; + + @Override + protected void setup(VaadinRequest request) { + final DateField df = new DateField(); + df.setId(DATEFIELD_ID); + addComponent(df); + } + + @Override + protected String getTestDescription() { + return "DateField popup should be closed when click on popup button"; + } + + @Override + protected Integer getTicketNumber() { + return 14857; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldPopupClosingTest.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldPopupClosingTest.java new file mode 100644 index 0000000000..ecbd6dd667 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldPopupClosingTest.java @@ -0,0 +1,42 @@ +package com.vaadin.tests.components.datefield; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.support.ui.ExpectedConditions; + +import com.vaadin.testbench.elements.DateFieldElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class DateFieldPopupClosingTest extends MultiBrowserTest { + /* + * try to open/close many times (not one time) because this defect is + * reproduced randomly (depends on timer) + */ + private static final int N = 100; + + @Test + public void testDateFieldPopupClosing() throws InterruptedException, + IOException { + openTestURL(); + + for (int i = 0; i < N; i++) { + clickDateDatePickerButton(); + + waitUntil(ExpectedConditions.visibilityOfElementLocated(By + .className("v-datefield-popup"))); + + clickDateDatePickerButton(); + + waitUntil(ExpectedConditions.invisibilityOfElementLocated(By + .className("v-datefield-popup"))); + } + } + + private void clickDateDatePickerButton() { + DateFieldElement dateField = $(DateFieldElement.class).first(); + dateField.findElement(By.tagName("button")).click(); + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/layout/EmptySpaceOnPageAfterExpandedComponent.java b/uitest/src/com/vaadin/tests/components/layout/EmptySpaceOnPageAfterExpandedComponent.java new file mode 100644 index 0000000000..c873a7efe7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/layout/EmptySpaceOnPageAfterExpandedComponent.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tests.components.layout; + +import com.vaadin.server.Page; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Panel; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.TextField; +import com.vaadin.ui.VerticalLayout; + +public class EmptySpaceOnPageAfterExpandedComponent extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + getLayout().setHeight("200px"); + + VerticalLayout container = new VerticalLayout(); + container.setStyleName("mystyle"); + container.setId("container"); + container.setSpacing(true); + container.setSizeFull(); + addComponent(container); + + Page.getCurrent().getStyles() + .add(".mystyle {border: 1px solid black;}"); + + GridLayout grid = new GridLayout(); + grid.setSpacing(true); + + TextField text1 = new TextField(); + text1.setCaption("Text1"); + text1.setRequired(true); + + grid.setColumns(1); + grid.setRows(1); + + grid.addComponent(text1); + + grid.setSizeUndefined(); + + Panel panel = new Panel(); + panel.setContent(grid); + + panel.setSizeUndefined(); + + container.addComponent(panel); + + TextArea expand = new TextArea(); + expand.setId("expandedElement"); + expand.setSizeFull(); + container.addComponent(expand); + + container.setExpandRatio(expand, 1); + } + + @Override + protected String getTestDescription() { + return "Height calculation should be correct in Chrome. There should not be any empty space after expanded component."; + } + + @Override + protected Integer getTicketNumber() { + return 12672; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/layout/EmptySpaceOnPageAfterExpandedComponentTest.java b/uitest/src/com/vaadin/tests/components/layout/EmptySpaceOnPageAfterExpandedComponentTest.java new file mode 100644 index 0000000000..09d19034e6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/layout/EmptySpaceOnPageAfterExpandedComponentTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.layout; + +import org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Test to make sure that there is no any empty space (in Google Chrome) on page + * after expanded component (#12672) + * + * Layout: + * + * [ Panel (auto x auto) [ Grid (auto x auto) ] + * + * AnyComponent (100% x 100%) + * + * <HERE SHOULD NOT BE ANY EMPTY SPACE> ] + * + * @author Vaadin Ltd + */ +public class EmptySpaceOnPageAfterExpandedComponentTest extends + MultiBrowserTest { + + @Test + public void testNoEmptySpaceOnPageAfterExpandedComponent() { + openTestURL(); + + final WebElement expandedElement = vaadinElementById("expandedElement"); + final WebElement containerElement = vaadinElementById("container"); + + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver input) { + int expandedElementBottom = expandedElement.getLocation() + .getY() + expandedElement.getSize().getHeight(); + int containerElementBottom = containerElement.getLocation() + .getY() + containerElement.getSize().getHeight(); + + return expandedElementBottom + 1 == containerElementBottom; + } + }); + } +} diff --git a/uitest/src/com/vaadin/tests/components/menubar/MenuBarsWithNesting.java b/uitest/src/com/vaadin/tests/components/menubar/MenuBarsWithNesting.java new file mode 100644 index 0000000000..16a0896aa2 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/menubar/MenuBarsWithNesting.java @@ -0,0 +1,125 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.menubar; + +import com.vaadin.server.FontAwesome; +import com.vaadin.server.Resource; +import com.vaadin.server.ThemeResource; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; +import com.vaadin.ui.MenuBar; +import com.vaadin.ui.MenuBar.MenuItem; + +/** + * A UI for testing VMenuBar.getSubPartElement(String). The UI contains two + * MenuBars, one without icons and one containing items with and without icons. + * Some of the icons are textual (using FontAwesome) and should behave like + * items with image icons: the icon should not be considered to be a part of the + * item's caption. + * + * @since + * @author Vaadin + */ +@SuppressWarnings("serial") +public class MenuBarsWithNesting extends AbstractTestUI { + + // The label displays the last selection. + private final Label label = new Label("Initial content"); + + // The captions and icons used in the second MenuBar. + public final static String[] itemNames = { "Icon item", "Arrow down", + "Arrow up", "Warning" }; + private final static Resource[] itemIcons = { + new ThemeResource("window/img/restore.png"), + FontAwesome.ARROW_DOWN, FontAwesome.ARROW_UP, FontAwesome.WARNING }; + + // The last menu item is nested with the following submenu items. + public final static String[] nestedItemnames = { "No icon", "Font icon", + "Image icon" }; + private final static Resource[] nestedItemIcons = { null, FontAwesome.LINK, + new ThemeResource("window/img/restore.png") }; + + private MenuBar.Command selectionCommand; + + @Override + protected void setup(VaadinRequest request) { + selectionCommand = new MenuBar.Command() { + @Override + public void menuSelected(MenuItem selectedItem) { + label.setValue(selectedItem.getText()); + } + }; + addComponent(createFirstMenuBar()); + addComponent(createSecondMenuBar()); + addComponent(label); + } + + /* + * Returns a menu bar with three levels of nesting but no icons. + */ + private MenuBar createFirstMenuBar() { + MenuBar menuBar = new MenuBar(); + MenuItem file = menuBar.addItem("File", null); + file.addItem("Open", selectionCommand); + file.addItem("Save", selectionCommand); + file.addItem("Save As..", selectionCommand); + file.addSeparator(); + MenuItem export = file.addItem("Export..", null); + export.addItem("As PDF...", selectionCommand); + export.addItem("As Doc...", selectionCommand); + file.addSeparator(); + file.addItem("Exit", selectionCommand); + + MenuItem edit = menuBar.addItem("Edit", null); + edit.addItem("Copy", selectionCommand); + edit.addItem("Cut", selectionCommand); + edit.addItem("Paste", selectionCommand); + + menuBar.addItem("Help", selectionCommand); + return menuBar; + } + + /* + * Returns a menu bar containing items with icons. The last menu item is + * nested and its submenu contains items with and without icons. + */ + private MenuBar createSecondMenuBar() { + MenuBar menuBar = new MenuBar(); + int n = itemNames.length; + for (int i = 0; i < n - 1; i++) { + menuBar.addItem(itemNames[i], itemIcons[i], selectionCommand); + } + MenuItem last = menuBar.addItem(itemNames[n - 1], itemIcons[n - 1], + null); + for (int i = 0; i < nestedItemnames.length; i++) { + last.addItem(nestedItemnames[i], nestedItemIcons[i], + selectionCommand); + } + return menuBar; + } + + @Override + protected String getTestDescription() { + return "This UI is used for testing subpart functionality of MenuBar. The " + + "functionality is used in TestBench tests."; + } + + @Override + protected Integer getTicketNumber() { + return 14879; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/menubar/MenuBarsWithNestingTest.java b/uitest/src/com/vaadin/tests/components/menubar/MenuBarsWithNestingTest.java new file mode 100644 index 0000000000..4c3383c5d6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/menubar/MenuBarsWithNestingTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.menubar; + +import static com.vaadin.tests.components.menubar.MenuBarsWithNesting.itemNames; +import static com.vaadin.tests.components.menubar.MenuBarsWithNesting.nestedItemnames; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.testbench.elements.MenuBarElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * This class tests the method VMenuBar.getSubPartElement(String) by using + * Vaadin locators for finding the items of a MenuBar. + * + * @since + * @author Vaadin Ltd + */ +public class MenuBarsWithNestingTest extends MultiBrowserTest { + private MenuBarElement firstMenuBar, secondMenuBar; + private LabelElement label; + + @Before + public void init() { + openTestURL(); + firstMenuBar = $(MenuBarElement.class).first(); + secondMenuBar = $(MenuBarElement.class).get(1); + label = $(LabelElement.class).get(1); + } + + @Test + public void testMenuWithoutIcons() { + WebElement fileMenu = firstMenuBar.findElement(By.vaadin("#File")); + fileMenu.click(); + WebElement exportMenu = fileMenu.findElement(By.vaadin("#Export..")); + exportMenu.click(); + waitUntil(ExpectedConditions.visibilityOfElementLocated(By + .xpath(".//*[text() = 'As PDF...']"))); + } + + @Test + public void testMenuWithIcons() throws InterruptedException { + // There is a separate test for the last item of the second menu. + for (int i = 0; i < itemNames.length - 1; i++) { + String itemName = itemNames[i]; + secondMenuBar.findElement(By.vaadin("#" + itemName)).click(); + waitUntil(ExpectedConditions.textToBePresentInElement( + label.getWrappedElement(), itemName)); + } + } + + @Test + public void testNestedMenuWithIcons() throws InterruptedException { + String selection = itemNames[itemNames.length - 1]; + for (String itemName : nestedItemnames) { + WebElement lastMenuItem = secondMenuBar.findElement(By.vaadin("#" + + selection)); + lastMenuItem.click(); + lastMenuItem.findElement(By.vaadin("#" + itemName)).click(); + waitUntil(ExpectedConditions.textToBePresentInElement( + label.getWrappedElement(), itemName)); + } + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/page/PageReload.java b/uitest/src/com/vaadin/tests/components/page/PageReload.java index c1799b29e3..033da4e0e8 100644 --- a/uitest/src/com/vaadin/tests/components/page/PageReload.java +++ b/uitest/src/com/vaadin/tests/components/page/PageReload.java @@ -2,7 +2,6 @@ package com.vaadin.tests.components.page; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUIWithLog; -import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; @@ -10,14 +9,12 @@ public class PageReload extends AbstractTestUIWithLog { @Override protected void setup(VaadinRequest request) { - Button b = new Button("Press to reload"); - b.addClickListener(new ClickListener() { + addButton("Press to reload", new ClickListener() { @Override public void buttonClick(ClickEvent event) { getPage().reload(); } }); - addComponent(b); log("UI id: " + getUIId()); } diff --git a/uitest/src/com/vaadin/tests/components/table/ContextMenuSize.java b/uitest/src/com/vaadin/tests/components/table/ContextMenuSize.java new file mode 100644 index 0000000000..ec7301099f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/ContextMenuSize.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.event.Action; +import com.vaadin.event.Action.Handler; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Table; + +/** + * Test UI for table context menu position and size. + * + * @author Vaadin Ltd + */ +public class ContextMenuSize extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + Table table = new Table(); + table.setPageLength(1); + table.addActionHandler(new Handler() { + + @Override + public void handleAction(Action action, Object sender, Object target) { + } + + @Override + public Action[] getActions(Object target, Object sender) { + return new Action[] { new Action("action1"), + new Action("action2"), new Action("action3"), + new Action("action4") }; + } + }); + BeanItemContainer<Bean> container = new BeanItemContainer<Bean>( + Bean.class); + container.addBean(new Bean()); + table.setContainerDataSource(container); + addComponent(table); + } + + @Override + public String getDescription() { + return "If context menu original position doesn't allow to show it then " + + "its bottom should be aligned with the window bottom and height " + + "should be reset after repositioning."; + } + + @Override + protected Integer getTicketNumber() { + return 14863; + } + + public static class Bean { + + public String getName() { + return "name"; + } + + public void setName() { + } + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java b/uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java new file mode 100644 index 0000000000..bb7001bc97 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/ContextMenuSizeTest.java @@ -0,0 +1,131 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Test for context menu position and size. + * + * @author Vaadin Ltd + */ +public class ContextMenuSizeTest extends MultiBrowserTest { + + @Test + public void testContextMenuBottom() { + openTestURL(); + + WebElement menu = openContextMenu(); + int initialHeight = menu.getSize().getHeight(); + int y = menu.getLocation().getY(); + + closeContextMenu(); + + Dimension size = getDriver().manage().window().getSize(); + + int windowHeight = y + initialHeight - 10; + if (isElementPresent(By.className("v-ff"))) { + // FF does something wrong with window height + windowHeight = y + initialHeight + 90; + } else if (isElementPresent(By.className("v-ch"))) { + // Chrome does something wrong with window height + windowHeight = y + initialHeight + 20; + } + getDriver().manage().window() + .setSize(new Dimension(size.getWidth(), windowHeight)); + + menu = openContextMenu(); + int height = menu.getSize().getHeight(); + + Assert.assertEquals("Context menu height has been changed after " + + "window height update which allows to show context as is", + initialHeight, height); + + } + + @Test + public void testContextMenuSize() { + openTestURL(); + + WebElement menu = openContextMenu(); + int initialHeight = menu.getSize().getHeight(); + int y = menu.getLocation().getY(); + + closeContextMenu(); + + Dimension size = getDriver().manage().window().getSize(); + + int windowHeight = initialHeight - 10; + if (isElementPresent(By.className("v-ch"))) { + // Chrome does something wrong with window height + windowHeight = y + initialHeight; + } + getDriver().manage().window() + .setSize(new Dimension(size.getWidth(), windowHeight)); + + menu = openContextMenu(); + int height = menu.getSize().getHeight(); + + Assert.assertTrue( + "Context menu height has not been descreased after " + + "window height update to value lower than context menu initial height", + initialHeight > height); + closeContextMenu(); + + getDriver().manage().window() + .setSize(new Dimension(size.getWidth(), size.getHeight())); + menu = openContextMenu(); + height = menu.getSize().getHeight(); + Assert.assertEquals("Context menu height has not been reset after " + + "window height reset", initialHeight, height); + } + + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + List<DesiredCapabilities> browsers = new ArrayList<DesiredCapabilities>( + getAllBrowsers()); + + // context menu doesn't work in phantom JS and works wired with IE8 and + // selenium. + browsers.remove(Browser.PHANTOMJS.getDesiredCapabilities()); + browsers.remove(Browser.IE8.getDesiredCapabilities()); + return browsers; + } + + private WebElement openContextMenu() { + Actions actions = new Actions(getDriver()); + actions.contextClick(findElement(By.className("v-table-cell-wrapper"))); + actions.perform(); + return findElement(By.className("v-contextmenu")); + } + + private void closeContextMenu() { + Actions actions = new Actions(getDriver()); + actions.click().build().perform(); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/FocusOnSelectedItem.java b/uitest/src/com/vaadin/tests/components/table/FocusOnSelectedItem.java index 4c0bea77ac..177f4d68fc 100644 --- a/uitest/src/com/vaadin/tests/components/table/FocusOnSelectedItem.java +++ b/uitest/src/com/vaadin/tests/components/table/FocusOnSelectedItem.java @@ -49,8 +49,7 @@ public class FocusOnSelectedItem extends AbstractTestUI { } addComponent(table); - Button button = new Button("Select"); - button.addClickListener(new Button.ClickListener() { + addButton("Select", new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { table.setValue("Item 198"); @@ -58,7 +57,6 @@ public class FocusOnSelectedItem extends AbstractTestUI { table.focus(); } }); - addComponent(button); } /* diff --git a/uitest/src/com/vaadin/tests/components/table/HeaderRightClickAfterDrag.java b/uitest/src/com/vaadin/tests/components/table/HeaderRightClickAfterDrag.java new file mode 100644 index 0000000000..e9c948ddf7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/HeaderRightClickAfterDrag.java @@ -0,0 +1,86 @@ +package com.vaadin.tests.components.table; + +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; +import com.vaadin.ui.Table; +import com.vaadin.ui.Window; + +public class HeaderRightClickAfterDrag extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + Table table = new Table(); + table.setContainerDataSource(new BeanItemContainer<TestBean>( + TestBean.class)); + for (int i = 0; i < 10; i++) { + table.addItem(new TestBean(i)); + } + + table.setPageLength(10); + table.setColumnReorderingAllowed(true); + table.addHeaderClickListener(new Table.HeaderClickListener() { + @Override + public void headerClick(Table.HeaderClickEvent event) { + if (MouseEventDetails.MouseButton.RIGHT.equals(event + .getButton())) { + Window window = new Window("Right-clicked:", new Label( + "<center>" + + event.getPropertyId().toString() + .toUpperCase() + "</center>", + ContentMode.HTML)); + window.setPositionX(event.getClientX()); + window.setPositionY(event.getClientY()); + window.setResizable(false); + addWindow(window); + } + } + }); + + addComponent(table); + } + + @Override + protected String getTestDescription() { + return "1) Right click a column header and see a popup<br>" + + "2) Reorder (or at least start dragging) that column<br>" + + "3) Right click that same column header, and you should get a popup again.<br>" + + "Before fix: no popup, unless you first left-click the header."; + } + + @Override + protected Integer getTicketNumber() { + return 15167; + } + + public class TestBean { + + private String foo, bar, baz, fiz; + + public TestBean(int i) { + foo = "Foo " + i; + bar = "Bar " + i; + baz = "Baz " + i; + fiz = "Fix " + i; + } + + public String getFoo() { + return foo; + } + + public String getBar() { + return bar; + } + + public String getBaz() { + return baz; + } + + public String getFiz() { + return fiz; + } + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/HeaderRightClickAfterDragTest.java b/uitest/src/com/vaadin/tests/components/table/HeaderRightClickAfterDragTest.java new file mode 100644 index 0000000000..f5f8bcce2a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/HeaderRightClickAfterDragTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.testbench.elements.WindowElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests whether right-click on a column header works after the column is + * dragged. + * + * @author Vaadin Ltd + */ +public class HeaderRightClickAfterDragTest extends MultiBrowserTest { + + @Test + public void dragAndRightClick() { + openTestURL(); + + waitForElementPresent(By.className("v-table")); + + TableElement table = $(TableElement.class).first(); + TestBenchElement header0 = table.getHeaderCell(0); + Actions actions = new Actions(getDriver()); + actions.contextClick(header0).perform(); + + // check that right-click opened a window + waitForElementPresent(By.className("v-window")); + + closeWindow(); + + actions.clickAndHold(header0).moveToElement(table.getHeaderCell(1)) + .release(); + + actions.contextClick(header0).perform(); + + // check that right-click still opened a window + waitForElementPresent(By.className("v-window")); + } + + private void closeWindow() { + WindowElement window = $(WindowElement.class).first(); + window.findElement(By.className("v-window-closebox")).click(); + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver driver) { + return findElements(By.className("v-window")).isEmpty(); + } + }); + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/LeftColumnAlignment.java b/uitest/src/com/vaadin/tests/components/table/LeftColumnAlignment.java index e783951d86..7789d0ae19 100644 --- a/uitest/src/com/vaadin/tests/components/table/LeftColumnAlignment.java +++ b/uitest/src/com/vaadin/tests/components/table/LeftColumnAlignment.java @@ -19,7 +19,6 @@ import com.vaadin.annotations.Theme; import com.vaadin.data.util.BeanItemContainer; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; -import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Table; @@ -53,15 +52,13 @@ public class LeftColumnAlignment extends AbstractTestUI { addComponent(table); - Button button = new Button("Align to Left"); - button.addClickListener(new ClickListener() { + addButton("Align to Left", new ClickListener() { @Override public void buttonClick(ClickEvent event) { table.setColumnAlignment("name", Align.LEFT); } }); - addComponent(button); } @Override diff --git a/uitest/src/com/vaadin/tests/components/table/TableCacheMinimizingOnFetchRows.java b/uitest/src/com/vaadin/tests/components/table/TableCacheMinimizingOnFetchRows.java new file mode 100644 index 0000000000..745f2344a3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableCacheMinimizingOnFetchRows.java @@ -0,0 +1,92 @@ +package com.vaadin.tests.components.table; + +import java.io.Serializable; +import java.util.List; + +import com.vaadin.data.util.BeanContainer; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Table; + +@SuppressWarnings("serial") +public class TableCacheMinimizingOnFetchRows extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + getLayout().setMargin(true); + + final Table table = new Table("Beans of All Sorts"); + + BeanContainer<String, Bean> beans = new BeanContainer<String, Bean>( + Bean.class) { + @Override + public List<String> getItemIds(int startIndex, int numberOfIds) { + + // numberOfIds should be about 60 after scrolling down the table + log.log("requested " + numberOfIds + " rows"); + + return super.getItemIds(startIndex, numberOfIds); + } + }; + beans.setBeanIdProperty("name"); + + for (int i = 0; i < 10000; i++) { + beans.addBean(new Bean("Common bean" + i, i)); + } + + table.setContainerDataSource(beans); + table.setPageLength(20); + table.setVisibleColumns(new Object[] { "name", "value" }); + table.setWidth("800px"); + + Button button = new Button("scroll down"); + button.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + table.setCurrentPageFirstItemIndex(table.size()); + } + }); + + addComponent(table); + addComponent(button); + } + + public class Bean implements Serializable { + + String name; + int value; + + public Bean(String name, int value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + } + + @Override + protected String getTestDescription() { + return "Ensure that when scrolling from top to bottom in a big table with 10000 items, not all rows in the range are cached"; + } + + @Override + protected Integer getTicketNumber() { + return 13576; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/table/TableCacheMinimizingOnFetchRowsTest.java b/uitest/src/com/vaadin/tests/components/table/TableCacheMinimizingOnFetchRowsTest.java new file mode 100644 index 0000000000..edb0f3851a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableCacheMinimizingOnFetchRowsTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TableCacheMinimizingOnFetchRowsTest extends MultiBrowserTest { + + @Test + public void testCacheSize() throws InterruptedException { + + openTestURL(); + + scrollToBottomOfTable(); + + // the row request might vary slightly with different browsers + String logtext1 = "requested 60 rows"; + String logtext2 = "requested 61 rows"; + + assertThat("Requested cached rows did not match expected", + logContainsText(logtext1) || logContainsText(logtext2)); + + } + + private void scrollToBottomOfTable() { + waitForElementPresent(By.className("v-button")); + $(ButtonElement.class).first().click(); + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableClickAndDragOnIconAndComponents.java b/uitest/src/com/vaadin/tests/components/table/TableClickAndDragOnIconAndComponents.java index 64f1a64558..4bdec81ccf 100644 --- a/uitest/src/com/vaadin/tests/components/table/TableClickAndDragOnIconAndComponents.java +++ b/uitest/src/com/vaadin/tests/components/table/TableClickAndDragOnIconAndComponents.java @@ -38,7 +38,7 @@ public class TableClickAndDragOnIconAndComponents extends AbstractTestUI { table.setId("testable-table"); addComponent(table); for (int i = 0; i < 5; i++) { - addItemAfter(i + "foo", null); + addItemAfter(i + "foo", null, false); } table.addGeneratedColumn("Label", new ColumnGenerator() { @@ -118,14 +118,15 @@ public class TableClickAndDragOnIconAndComponents extends AbstractTestUI { IndexedContainer container = (IndexedContainer) table .getContainerDataSource(); + boolean selected = table.getValue().equals(dragged); container.removeItem(dragged); - addItemAfter(dragged, target); + addItemAfter(dragged, target, selected); } }); } @SuppressWarnings("unchecked") - private void addItemAfter(Object itemId, Object afterItemId) { + private void addItemAfter(Object itemId, Object afterItemId, boolean select) { Item item; if (afterItemId != null) { item = table.addItemAfter(afterItemId, itemId); @@ -136,6 +137,9 @@ public class TableClickAndDragOnIconAndComponents extends AbstractTestUI { item.getItemProperty("red").setValue("red " + itemId); item.getItemProperty("icon").setValue( new ThemeResource("../runo/icons/16/ok.png")); + if (select) { + table.select(itemId); + } } @Override diff --git a/uitest/src/com/vaadin/tests/components/table/TableDeleteSelectedRow.java b/uitest/src/com/vaadin/tests/components/table/TableDeleteSelectedRow.java new file mode 100644 index 0000000000..349fbc73fe --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableDeleteSelectedRow.java @@ -0,0 +1,117 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import java.util.Collection; + +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.MultiSelectMode; +import com.vaadin.tests.components.AbstractTestUI; +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.Table; + +/** + * Test UI for delete rows operation in multiselect table. + * + * @author Vaadin Ltd + */ +public class TableDeleteSelectedRow extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final Table table = new Table(); + table.setSelectable(true); + table.setImmediate(true); + + BeanItemContainer<TableBean> container = createContainer(); + + table.setContainerDataSource(container); + + final Label selectedSize = new Label(); + selectedSize.addStyleName("selected-rows"); + + Button changeMode = new Button("Set multiselect", new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + table.setMultiSelect(true); + table.setMultiSelectMode(MultiSelectMode.SIMPLE); + + BeanItemContainer<TableBean> container = createContainer(); + + table.setContainerDataSource(container); + } + }); + changeMode.addStyleName("multiselect"); + + Button delete = new Button("Delete selected", new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + if (table.getValue() instanceof Collection) { + Collection<?> rows = (Collection<?>) table.getValue(); + for (Object row : rows) { + table.getContainerDataSource().removeItem(row); + } + rows = (Collection<?>) table.getValue(); + selectedSize.setValue(String.valueOf(rows.size())); + } else { + table.getContainerDataSource().removeItem(table.getValue()); + selectedSize.setValue(table.getValue() == null ? "0" : "1"); + } + } + }); + delete.addStyleName("delete"); + + addComponents(delete, changeMode, selectedSize, table); + } + + @Override + protected String getTestDescription() { + return "Items deleted via container data source should not be available as selected in the table."; + } + + @Override + protected Integer getTicketNumber() { + return 13580; + } + + private BeanItemContainer<TableBean> createContainer() { + BeanItemContainer<TableBean> container = new BeanItemContainer<TableBean>( + TableBean.class); + container.addBean(new TableBean("first")); + container.addBean(new TableBean("second")); + container.addBean(new TableBean("third")); + return container; + } + + public static class TableBean { + + TableBean(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + private String name; + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableDeleteSelectedRowTest.java b/uitest/src/com/vaadin/tests/components/table/TableDeleteSelectedRowTest.java new file mode 100644 index 0000000000..0e807edf14 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableDeleteSelectedRowTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Test to check selected rows in multiselect table after deletion. + * + * @author Vaadin Ltd + */ +public class TableDeleteSelectedRowTest extends MultiBrowserTest { + + @Test + public void deleteSelectedRows() { + openTestURL(); + + // Select row in the table + findElement(By.className("v-table-row-odd")).click(); + + // Delete selected row + findElement(By.className("delete")).click(); + + WebElement selectedSize = findElement(By.className("selected-rows")); + int size = Integer.parseInt(selectedSize.getText()); + + Assert.assertEquals( + "Non empty collection of selected rows after remove via container", + 0, size); + + // Reset table and set multiselect mode + findElement(By.className("multiselect")).click(); + + // Select row in the table + findElement(By.className("v-table-row-odd")).click(); + + // Delete selected row + findElement(By.className("delete")).click(); + + selectedSize = findElement(By.className("selected-rows")); + size = Integer.parseInt(selectedSize.getText()); + + Assert.assertEquals( + "Non empty collection of selected rows after remove via container", + 0, size); + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableExpandRatio.java b/uitest/src/com/vaadin/tests/components/table/TableExpandRatio.java new file mode 100644 index 0000000000..92c9b8d988 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableExpandRatio.java @@ -0,0 +1,110 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import java.util.Arrays; + +import com.vaadin.annotations.PreserveOnRefresh; +import com.vaadin.annotations.Theme; +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Table; +import com.vaadin.ui.VerticalLayout; + +@PreserveOnRefresh +@Theme("valo") +public class TableExpandRatio extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + + BeanItemContainer<MyItem> container = new BeanItemContainer<TableExpandRatio.MyItem>( + MyItem.class, Arrays.asList(new MyItem("one", 1), new MyItem( + "two", 2))); + + final Table table = new Table(null, container); + + table.setWidth("800px"); + table.setImmediate(true); + + Button widthButton = new Button("Set Width", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + table.setColumnWidth("value", 300); + + } + }); + + Button expandButton = new Button("Set Expand Ratio", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + table.setColumnExpandRatio("value", 1); + + } + }); + + widthButton.setId("widthbutton"); + expandButton.setId("expandbutton"); + + VerticalLayout layout = new VerticalLayout(widthButton, expandButton, + table); + addComponent(layout); + } + + public class MyItem { + + private String name; + private Integer value; + + public MyItem(String name, Integer value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getValue() { + return value; + } + + public void setValue(Integer value) { + this.value = value; + } + } + + @Override + protected String getTestDescription() { + return "When a column has fixed width and it is changed to expand ratio, the width should update accordingly"; + } + + @Override + protected Integer getTicketNumber() { + return 15101; + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableExpandRatioTest.java b/uitest/src/com/vaadin/tests/components/table/TableExpandRatioTest.java new file mode 100644 index 0000000000..3cf66d4e4b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableExpandRatioTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.number.IsCloseTo.closeTo; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TableExpandRatioTest extends MultiBrowserTest { + + @Override + public void setup() throws Exception { + super.setup(); + + openTestURL(); + } + + /* + * Needed for IE to get focus when button is clicked + */ + @Override + protected boolean requireWindowFocusForIE() { + + return true; + } + + @Test + public void cellWidthUpdatesWhenExpandRatioSetAfterDefinedWidth() { + + // test that after setting defined size to the second column, the first + // column will have correct size + + setDefinedWidth(); + + assertThat(getFirstCellWidth(), closeTo(500, 10)); + + // test that after setting expandratio to the second column, it is + // correct + + setExpandRatio(); + + assertThat(getFirstCellWidth(), closeTo(65, 5)); + + } + + private void setExpandRatio() { + $(ButtonElement.class).id("expandbutton").click(); + } + + private void setDefinedWidth() { + $(ButtonElement.class).id("widthbutton").click(); + } + + private double getFirstCellWidth() { + + List<WebElement> rows = $(TableElement.class).first() + .findElement(By.className("v-table-body")) + .findElements(By.tagName("tr")); + WebElement firstrow = rows.get(0); + List<WebElement> cells = firstrow.findElements(By + .className("v-table-cell-content")); + + int cellwidth = cells.get(0).getSize().getWidth(); + return cellwidth; + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRows.java b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRows.java index df06580dae..bee0839663 100644 --- a/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRows.java +++ b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRows.java @@ -115,11 +115,11 @@ public class TableRepairsScrollPositionOnReAddingAllRows extends AbstractTestUI } }); - Button buttonReplaceByWholeSubsetPlusOnNew = new Button( + Button buttonReplaceByWholeSubsetPlusOneNew = new Button( "Replace rows by whole subset plus one new item"); - buttonReplaceByWholeSubsetPlusOnNew - .setId("buttonReplaceByWholeSubsetPlusOnNew"); - buttonReplaceByWholeSubsetPlusOnNew + buttonReplaceByWholeSubsetPlusOneNew + .setId("buttonReplaceByWholeSubsetPlusOneNew"); + buttonReplaceByWholeSubsetPlusOneNew .addClickListener(new ClickListener() { @Override @@ -136,6 +136,40 @@ public class TableRepairsScrollPositionOnReAddingAllRows extends AbstractTestUI } }); + Button buttonRemoveAllAddOne = new Button( + "Remove all items and add only one new item"); + buttonRemoveAllAddOne.setId("buttonRemoveAllAddOne"); + buttonRemoveAllAddOne.addClickListener(new ClickListener() { + + @Override + public void buttonClick(com.vaadin.ui.Button.ClickEvent event) { + cont.removeAllItems(); + TableItem ti = new TableItem(); + ti.setName("Item_" + 20); + cont.addBean(ti); + } + }); + + // This should be the last test as it changes the table datasource + Button buttonReplaceByNewDatasource = new Button( + "Remove all items and add new datasource"); + buttonReplaceByNewDatasource.setId("buttonReplaceByNewDatasource"); + buttonReplaceByNewDatasource.addClickListener(new ClickListener() { + + @Override + public void buttonClick(com.vaadin.ui.Button.ClickEvent event) { + cont.removeAllItems(); + BeanItemContainer<TableItem> newContainer = new BeanItemContainer<TableItem>( + TableItem.class); + for (int i = 0; i < 50; i++) { + TableItem ti = new TableItem(); + ti.setName("Item_" + i); + newContainer.addBean(ti); + } + table.setContainerDataSource(newContainer); + } + }); + for (int i = 0; i < 80; i++) { TableItem ti = new TableItem(); ti.setName("Item_" + i); @@ -147,7 +181,9 @@ public class TableRepairsScrollPositionOnReAddingAllRows extends AbstractTestUI getLayout().addComponent(buttonReplaceByAnotherCollectionViaAddAll); getLayout().addComponent(buttonReplaceByAnotherCollectionViaAdd); getLayout().addComponent(buttonReplaceBySubsetOfSmallerSize); - getLayout().addComponent(buttonReplaceByWholeSubsetPlusOnNew); + getLayout().addComponent(buttonReplaceByWholeSubsetPlusOneNew); + getLayout().addComponent(buttonRemoveAllAddOne); + getLayout().addComponent(buttonReplaceByNewDatasource); getLayout().addComponent(buttonRestore); getLayout().addComponent(table); } diff --git a/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRowsTest.java b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRowsTest.java index a3e7f29dfe..4ca3ed406b 100644 --- a/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRowsTest.java +++ b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRowsTest.java @@ -18,17 +18,10 @@ package com.vaadin.tests.components.table; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.number.IsCloseTo.closeTo; +import org.junit.Before; import org.junit.Test; -import org.openqa.selenium.By; -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.ExpectedCondition; -import com.vaadin.testbench.commands.TestBenchCommandExecutor; import com.vaadin.testbench.elements.TableElement; -import com.vaadin.testbench.screenshot.ImageComparison; -import com.vaadin.testbench.screenshot.ReferenceNameGenerator; import com.vaadin.tests.tb3.MultiBrowserTest; /** @@ -40,138 +33,127 @@ import com.vaadin.tests.tb3.MultiBrowserTest; public class TableRepairsScrollPositionOnReAddingAllRowsTest extends MultiBrowserTest { - @Test - public void testScrollRepairsAfterReAddingAllRows() - throws InterruptedException { - openTestURL(); - - WebElement row0 = $(TableElement.class).first().getCell(0, 0); - int rowLocation0 = row0.getLocation().getY(); + private int rowLocation0; - // case 1 - scrollUp(); + @Override + @Before + public void setup() throws Exception { + super.setup(); + openTestURL(); - waitUntilNot(new ExpectedCondition<Boolean>() { - @Override - public Boolean apply(WebDriver input) { - return $(TableElement.class).first().getCell(48, 0) == null; - } - }, 10); + rowLocation0 = getCellY(0); + scrollToBottom(); + } - WebElement row = $(TableElement.class).first().getCell(48, 0); - int rowLocation = row.getLocation().getY(); + @Test + public void testReAddAllViaAddAll() { + int rowLocation = getCellY(70); // This button is for re-adding all rows (original itemIds) at once // (removeAll() + addAll()) hitButton("buttonReAddAllViaAddAll"); - row = $(TableElement.class).first().getCell(48, 0); - int newRowLocation = row.getLocation().getY(); + int newRowLocation = getCellY(70); - // ranged check because IE9 consistently misses the mark by 1 pixel - assertThat( + assertCloseTo( "Scroll position should be the same as before Re-Adding rows via addAll()", - (double) newRowLocation, - closeTo(rowLocation, row.getSize().height + 1)); - - // case 2 - scrollUp(); + newRowLocation, rowLocation); - waitUntilNot(new ExpectedCondition<Boolean>() { - @Override - public Boolean apply(WebDriver input) { - return $(TableElement.class).first().getCell(48, 0) == null; - } - }, 10); + } - row = $(TableElement.class).first().getCell(48, 0); - rowLocation = row.getLocation().getY(); + @Test + public void testReplaceByAnotherCollectionViaAddAll() { + int rowLocation = getCellY(70); // This button is for replacing all rows at once (removeAll() + // addAll()) hitButton("buttonReplaceByAnotherCollectionViaAddAll"); - row = $(TableElement.class).first().getCell(48, 0); - newRowLocation = row.getLocation().getY(); + // new collection has one less element + int newRowLocation = getCellY(69); - // ranged check because IE9 consistently misses the mark by 1 pixel - assertThat( + assertCloseTo( "Scroll position should be the same as before Replacing rows via addAll()", - (double) newRowLocation, - closeTo(rowLocation, row.getSize().height + 1)); + newRowLocation, rowLocation); + } + + @Test + public void testReplaceByAnotherCollectionViaAdd() { - // case 3 // This button is for replacing all rows one by one (removeAll() + add() // + add()..) hitButton("buttonReplaceByAnotherCollectionViaAdd"); - row = $(TableElement.class).first().getCell(0, 0); - newRowLocation = row.getLocation().getY(); + int newRowLocation = getCellY(0); - // ranged check because IE9 consistently misses the mark by 1 pixel - assertThat("Scroll position should be 0", (double) newRowLocation, - closeTo(rowLocation0, 1)); - - // case 4 - // This button is for restoring initial list and for scrolling to 0 - // position - hitButton("buttonRestore"); - scrollUp(); - - waitUntilNot(new ExpectedCondition<Boolean>() { - @Override - public Boolean apply(WebDriver input) { - return $(TableElement.class).first().getCell(48, 0) == null; - } - }, 10); + assertCloseTo("Scroll position should be 0", newRowLocation, + rowLocation0); + } + @Test + public void testReplaceBySubsetOfSmallerSize() { // This button is for replacing all rows at once but the count of rows // is less then first index to scroll hitButton("buttonReplaceBySubsetOfSmallerSize"); - row = $(TableElement.class).first().getCell(5, 0); + int newRowLocation = getCellY(5); - newRowLocation = row.getLocation().getY(); + assertCloseTo("Scroll position should be 0", newRowLocation, + rowLocation0); + } - // ranged check because IE9 consistently misses the mark by 1 pixel - assertThat("Scroll position should be 0", (double) newRowLocation, - closeTo(rowLocation0, 1)); + @Test + public void testReplaceByWholeSubsetPlusOneNew() { + int rowLocation = getCellY(70); - // case 5 - // This button is for restoring initial list and for scrolling to 0 - // position - hitButton("buttonRestore"); - scrollUp(); + // This button is for replacing by whole original sub-set of items plus + // one new + hitButton("buttonReplaceByWholeSubsetPlusOneNew"); - waitUntilNot(new ExpectedCondition<Boolean>() { - @Override - public Boolean apply(WebDriver input) { - return $(TableElement.class).first().getCell(48, 0) == null; - } - }, 10); + int newRowLocation = getCellY(70); - row = $(TableElement.class).first().getCell(48, 0); - rowLocation = row.getLocation().getY(); + assertCloseTo("Scroll position should be the same as before Replacing", + newRowLocation, rowLocation); - // This button is for replacing by whole original sub-set of items plus - // one new - hitButton("buttonReplaceByWholeSubsetPlusOnNew"); + } - row = $(TableElement.class).first().getCell(48, 0); - newRowLocation = row.getLocation().getY(); + @Test + public void testRemoveAllAddOne() { + // This button is for removing all and then adding only one new item + hitButton("buttonRemoveAllAddOne"); - // ranged check because IE9 consistently misses the mark by 1 pixel - assertThat("Scroll position should be the same as before Replacing", - (double) newRowLocation, - closeTo(rowLocation, row.getSize().height + 1)); + int newRowLocation = getCellY(0); + + assertCloseTo("Scroll position should be 0", newRowLocation, + rowLocation0); + } + + @Test + public void testReplaceByNewDatasource() { + // This button is for remove all items and add new datasource + hitButton("buttonReplaceByNewDatasource"); + + int newRowLocation = getCellY(0); + + assertCloseTo("Scroll position should be 0", newRowLocation, + rowLocation0); + } + + private TableElement getTable() { + return $(TableElement.class).first(); + } + private void scrollToBottom() { + scrollTable(getTable(), 80, 70); } - private void scrollUp() { - WebElement actualElement = getDriver().findElement( - By.className("v-table-body-wrapper")); - JavascriptExecutor js = new TestBenchCommandExecutor(getDriver(), - new ImageComparison(), new ReferenceNameGenerator()); - js.executeScript("arguments[0].scrollTop = " + 1205, actualElement); + private int getCellY(int row) { + return getTable().getCell(row, 0).getLocation().getY(); } + + private void assertCloseTo(String reason, int actual, int expected) { + // ranged check because IE9 consistently misses the mark by 1 pixel + assertThat(reason, (double) actual, closeTo(expected, 1)); + } + } diff --git a/uitest/src/com/vaadin/tests/components/table/TableWidthItemRemove.java b/uitest/src/com/vaadin/tests/components/table/TableWidthItemRemove.java index 79a85cd49b..bd84fab309 100644 --- a/uitest/src/com/vaadin/tests/components/table/TableWidthItemRemove.java +++ b/uitest/src/com/vaadin/tests/components/table/TableWidthItemRemove.java @@ -17,7 +17,6 @@ package com.vaadin.tests.components.table; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; -import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Table; @@ -46,17 +45,14 @@ public class TableWidthItemRemove extends AbstractTestUI { table.setColumnWidth("lastName", 100); table.setColumnWidth("year", 50); - Button cleanButton = new Button("Clean"); - cleanButton.addClickListener(new ClickListener() { + addButton("Clean", new ClickListener() { @Override public void buttonClick(ClickEvent event) { table.removeAllItems(); } }); - addComponent(cleanButton); - Button populateButton = new Button("Populate"); - populateButton.addClickListener(new ClickListener() { + addButton("Populate", new ClickListener() { @Override public void buttonClick(ClickEvent event) { table.addItem( @@ -64,7 +60,6 @@ public class TableWidthItemRemove extends AbstractTestUI { Math.random() * 1000); } }); - addComponent(populateButton); addComponent(table); } diff --git a/uitest/src/com/vaadin/tests/components/table/UpdateTableWhenUnfocused.java b/uitest/src/com/vaadin/tests/components/table/UpdateTableWhenUnfocused.java new file mode 100644 index 0000000000..231375c2ea --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/UpdateTableWhenUnfocused.java @@ -0,0 +1,67 @@ +package com.vaadin.tests.components.table; + +import com.vaadin.data.Container; +import com.vaadin.data.Item; +import com.vaadin.data.util.IndexedContainer; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.Table; + +public class UpdateTableWhenUnfocused extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + + final Table table = createTable(); + + TabSheet tabSheet = new TabSheet(); + tabSheet.addTab(table, "tab1"); + tabSheet.setHeight("5000px"); + tabSheet.setWidth("100%"); + addComponent(tabSheet); + + final Button button = new Button("Refresh table"); + button.addClickListener(new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + button.focus(); + table.refreshRowCache(); + } + }); + addComponent(button); + + } + + private Table createTable() { + Table table = new Table("Table"); + table.setImmediate(true); + table.setMultiSelect(true); + table.setSizeFull(); + table.setSelectable(true); + + Container ds = new IndexedContainer(); + ds.addContainerProperty("column", Integer.class, null); + for (int i = 0; i < 500; i++) { + Item item = ds.addItem(i); + item.getItemProperty("column").setValue(i); + } + table.setContainerDataSource(ds); + + return table; + } + + @Override + protected String getTestDescription() { + return "Clicking the button after selecting a row in the table should not cause the window to scroll."; + } + + @Override + protected Integer getTicketNumber() { + return 12976; + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/table/UpdateTableWhenUnfocusedTest.java b/uitest/src/com/vaadin/tests/components/table/UpdateTableWhenUnfocusedTest.java new file mode 100644 index 0000000000..fcd73f541d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/UpdateTableWhenUnfocusedTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.IOException; + +import org.junit.Test; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class UpdateTableWhenUnfocusedTest extends MultiBrowserTest { + + @Test + public void testWindowIsNotScrolled() throws IOException { + openTestURL(); + + TestBenchElement cell = $(TableElement.class).first().getCell(3, 0); + cell.click(); + + TestBenchElement button = $(ButtonElement.class).first(); + button.focus(); + + int buttonLocation = button.getLocation().getY(); + + button.click(); + + int newButtonLocation = button.getLocation().getY(); + + assertThat( + "Button location has changed after table refresh, window has scrolled and it shouldn't have", + newButtonLocation, is(buttonLocation)); + + } +} diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSelectionRevertedByServer.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSelectionRevertedByServer.java index b51a8dde08..0d7ec48a99 100644 --- a/uitest/src/com/vaadin/tests/components/tabsheet/TabSelectionRevertedByServer.java +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSelectionRevertedByServer.java @@ -2,7 +2,6 @@ package com.vaadin.tests.components.tabsheet; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; -import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; @@ -59,15 +58,13 @@ public class TabSelectionRevertedByServer extends AbstractTestUI { addComponent(tabsheet); - Button button = new Button("Select Last Tab"); - button.addClickListener(new ClickListener() { + addButton("Select Last Tab", new ClickListener() { @Override public void buttonClick(ClickEvent event) { tabsheet.setSelectedTab(lastTab); } }); - addComponent(button); } @Override diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetClose.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetClose.java new file mode 100644 index 0000000000..2cadde567f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetClose.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.tabsheet; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.CssLayout; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.TabSheet.Tab; + +/** + * This test UI is used for checking that when a tab is closed, another one is + * scrolled into view. + * + * @since + * @author Vaadin Ltd + */ +public class TabSheetClose extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + TabSheet tabsheet = new TabSheet(); + for (int loop = 0; loop < 3; loop++) { + Tab tab = tabsheet.addTab(new CssLayout(), "tab " + loop); + tab.setClosable(true); + tab.setId("tab" + loop); + } + CssLayout layout = new CssLayout(); + layout.addComponent(tabsheet); + layout.setWidth("150px"); + addComponent(layout); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "When all tabs have not been closed, at least one tab should be visible. "; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 14348; + } +} diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetCloseTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetCloseTest.java new file mode 100644 index 0000000000..5314038d72 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetCloseTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.tabsheet; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests that when closing the last tab on a TabSheet, another tab gets selected + * with no error. Only the last tab should be visible, so the actual TabSheet + * width should be small. + * + * @since + * @author Vaadin Ltd + */ +public class TabSheetCloseTest extends MultiBrowserTest { + + private static final String TAB_CLOSE = "//span[@class = 'v-tabsheet-caption-close']"; + private static final String LAST_TAB = "//*[@id = 'tab2']/div/div"; + private static final String SCROLLER_NEXT = "//button[@class = 'v-tabsheet-scrollerNext']"; + private static final String FIRST_TAB = "//*[@id = 'tab0']"; + private static final String SECOND_TAB = "//*[@id = 'tab1']"; + + @Test + public void testClosingOfLastTab() throws Exception { + openTestURL(); + + // Click next button twice to get to the last tab + findElement(By.xpath(SCROLLER_NEXT)).click(); + findElement(By.xpath(SCROLLER_NEXT)).click(); + + findElement(By.xpath(LAST_TAB)).click(); + + // Closing last tab will take back to the second tab. Closing that + // will leave the first tab visible. + findElements(By.xpath(TAB_CLOSE)).get(2).click(); + assertTrue(findElement(By.xpath(SECOND_TAB)).isDisplayed()); + findElements(By.xpath(TAB_CLOSE)).get(1).click(); + assertTrue(findElement(By.xpath(FIRST_TAB)).isDisplayed()); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetScrollOnTabClose.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetScrollOnTabClose.java new file mode 100644 index 0000000000..1400100f3b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetScrollOnTabClose.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.tabsheet; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.CssLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.TabSheet.Tab; + +/** + * This testUI is used for testing that the scroll position of a tab sheet does + * not change when tabs are removed. The exception is removing the leftmost + * visible tab. + * + * @since + * @author Vaadin Ltd + */ +public class TabSheetScrollOnTabClose extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + final TabSheet tabSheet = new TabSheet(); + for (int i = 0; i < 10; i++) { + Tab tab = tabSheet.addTab(new CssLayout(), "tab " + i); + tab.setClosable(true); + tab.setId("tab" + i); + } + tabSheet.setWidth(250, Unit.PIXELS); + addComponent(tabSheet); + addComponent(new Label("Close tab number")); + for (int i = 0; i < 10; i++) { + final String tabCaption = "tab " + i; + final Button b = new Button("" + i); + b.addClickListener(new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + b.setEnabled(false); + tabSheet.removeTab(getTab(tabSheet, tabCaption)); + } + }); + addComponent(b); + } + } + + private Tab getTab(TabSheet ts, String tabCaption) { + for (int i = 0; i < ts.getComponentCount(); i++) { + String caption = ts.getTab(i).getCaption(); + if (tabCaption.equals(caption)) { + return ts.getTab(i); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Scroll position should not change when closing tabs."; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 14348; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetScrollOnTabCloseTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetScrollOnTabCloseTest.java new file mode 100644 index 0000000000..8247b436d0 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetScrollOnTabCloseTest.java @@ -0,0 +1,171 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.tabsheet; + +import java.util.List; +import java.util.NoSuchElementException; + +import org.junit.Test; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.TabSheetElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests removing tabs that have been scrolled out of view. This should cause no + * change to the scroll position. + * + * @since + * @author Vaadin Ltd + */ +public class TabSheetScrollOnTabCloseTest extends MultiBrowserTest { + + @Test + public void testScrollPositionAfterClosing() throws Exception { + openTestURL(); + TabSheetElement ts = $(TabSheetElement.class).first(); + WebElement tabSheetScroller = ts.findElement(By + .className("v-tabsheet-scrollerNext")); + // scroll to the right + for (int i = 0; i < 4; i++) { + tabSheetScroller.click(); + } + // check that tab 4 is the first visible tab + checkDisplayedStatus(ts, "tab3", false); + checkDisplayedStatus(ts, "tab4", true); + // remove tabs from the left, check that tab4 is still the first visible + // tab + for (int i = 0; i < 4; i++) { + $(ButtonElement.class).get(i).click(); + checkDisplayedStatus(ts, "tab3" + i, false); + checkDisplayedStatus(ts, "tab4", true); + checkDisplayedStatus(ts, "tab6", true); + } + // remove tabs from the right and check scroll position + for (int i = 7; i < 10; i++) { + $(ButtonElement.class).get(i).click(); + checkFirstTab(ts, "tab4"); + checkDisplayedStatus(ts, "tab6", true); + } + } + + /** + * Checks that the visible status of the tab with the given id is equal to + * shouldBeVisible. That is, the tab with the given id should be visible if + * and only if shouldBeVisible is true. Used for checking that the leftmost + * visible tab is the expected one when there should be tabs (hidden because + * of scroll position) to the left of tabId. + * + * If there is no tab with the specified id, the tab is considered not to be + * visible. + */ + private void checkDisplayedStatus(TabSheetElement tabSheet, String tabId, + boolean shouldBeVisible) { + org.openqa.selenium.By locator = By.cssSelector("#" + tabId); + waitUntil(visibilityOfElement(locator, shouldBeVisible)); + } + + /** + * Checks that there are no hidden tabs in tabSheet and that the id of the + * first tab is tabId. Used for checking that the leftmost visible tab is + * the expected one when there are no tabs to the left of the tab with the + * given id. When there are tabs to the left of tabId, check instead that + * tabId is visible and the previous tab is hidden (see + * checkDisplayedStatus). + */ + private void checkFirstTab(TabSheetElement tabSheet, String tabId) { + waitUntil(visibilityOfElement( + By.cssSelector(".v-tabsheet-tabitemcell[aria-hidden]"), false)); + waitUntil(leftmostTabHasId(tabSheet, tabId)); + } + + /** + * An expectation for checking that the visibility status of the specified + * element is correct. If the element does not exist in the DOM, it is + * considered not to be visible. If several elements match the locator, only + * the visibility of the first matching element is considered. + * + * @param locator + * used to find the element + * @param expectedVisibility + * whether the element should be visible + */ + private static ExpectedCondition<Boolean> visibilityOfElement( + final org.openqa.selenium.By locator, + final boolean expectedVisibility) { + return new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver driver) { + List<WebElement> matchingElements = driver + .findElements(locator); + if (matchingElements.isEmpty()) { + return !expectedVisibility; + } else { + try { + WebElement first = matchingElements.get(0); + return first.isDisplayed() == expectedVisibility; + } catch (StaleElementReferenceException e) { + // The element was initially in DOM but has been + // removed. + return !expectedVisibility; + } + } + } + + @Override + public String toString() { + return "element " + (expectedVisibility ? "" : "not ") + + "expected to be visible: " + locator; + } + }; + } + + /** + * An expectation for checking that the leftmost tab has id equal to tabId. + * + * @param tabSheet + * the tab sheet containing the tab + * @param tabId + * the id of the tab that should be the leftmost tab + */ + private static ExpectedCondition<Boolean> leftmostTabHasId( + final TabSheetElement tabSheet, final String tabId) { + return new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver driver) { + try { + WebElement leftElement = tabSheet.findElement(By + .cssSelector(".v-tabsheet-tabitemcell")); + String leftId = leftElement.getAttribute("id"); + return leftId.equals(tabId); + } catch (NoSuchElementException e) { + return false; + } + } + + @Override + public String toString() { + return "expected tab index of the leftmost tab in the tab sheet: " + + tabId; + } + }; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/tree/TreeItemDoubleClick.java b/uitest/src/com/vaadin/tests/components/tree/TreeItemDoubleClick.java index 8b7890e63c..9031a76e66 100644 --- a/uitest/src/com/vaadin/tests/components/tree/TreeItemDoubleClick.java +++ b/uitest/src/com/vaadin/tests/components/tree/TreeItemDoubleClick.java @@ -32,8 +32,7 @@ public class TreeItemDoubleClick extends AbstractTestUIWithLog { addComponent(tree); - Button button = new Button("Change immediate flag"); - button.addClickListener(new Button.ClickListener() { + addButton("Change immediate flag", new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { @@ -44,8 +43,6 @@ public class TreeItemDoubleClick extends AbstractTestUIWithLog { }); - addComponent(button); - } @Override diff --git a/uitest/src/com/vaadin/tests/components/ui/VaadinFinderLocatorUISearchTest.java b/uitest/src/com/vaadin/tests/components/ui/VaadinFinderLocatorUISearchTest.java new file mode 100644 index 0000000000..37766dd060 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/VaadinFinderLocatorUISearchTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.elements.UIElement; +import com.vaadin.tests.components.button.ButtonClick; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class VaadinFinderLocatorUISearchTest extends MultiBrowserTest { + + @Override + protected Class<?> getUIClass() { + return ButtonClick.class; + } + + @Test + public void getUIElementTest() { + openTestURL(); + UIElement ui = $(UIElement.class).first(); + Assert.assertNotNull("Couldn't find the UI Element on the page", ui); + } +} diff --git a/uitest/src/com/vaadin/tests/components/upload/DisabledUploadButton.java b/uitest/src/com/vaadin/tests/components/upload/DisabledUploadButton.java new file mode 100644 index 0000000000..dcf2ac2784 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/upload/DisabledUploadButton.java @@ -0,0 +1,41 @@ +package com.vaadin.tests.components.upload; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Upload; + +public class DisabledUploadButton extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final Upload upload = new Upload(); + + addComponent(upload); + + addButton("Set readonly", new Button.ClickListener() { + @Override + public void buttonClick(Button.ClickEvent event) { + upload.setReadOnly(true); + } + }); + + addButton("Set disabled", new Button.ClickListener() { + @Override + public void buttonClick(Button.ClickEvent event) { + upload.setEnabled(false); + } + }); + } + + @Override + public String getDescription() { + return "Upload button should be disabled when upload " + + "is set to readonly and/or disabled"; + } + + @Override + protected Integer getTicketNumber() { + return 14655; + } +} diff --git a/uitest/src/com/vaadin/tests/components/upload/DisabledUploadButtonTest.java b/uitest/src/com/vaadin/tests/components/upload/DisabledUploadButtonTest.java new file mode 100644 index 0000000000..cc97b4d7d1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/upload/DisabledUploadButtonTest.java @@ -0,0 +1,55 @@ +package com.vaadin.tests.components.upload; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.UploadElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class DisabledUploadButtonTest extends MultiBrowserTest { + + @Override + public void setup() throws Exception { + super.setup(); + openTestURL(); + } + + private String getUploadButtonClass() { + WebElement uploadButton = getUploadButton(); + + return uploadButton.getAttribute("class"); + } + + private void clickButton(String caption) { + $(ButtonElement.class).caption(caption).first().click(); + } + + private WebElement getUploadButton() { + UploadElement upload = $(UploadElement.class).first(); + return upload.findElement(By.className("v-button")); + } + + @Test + public void buttonIsReadonly() { + assertThat(getUploadButtonClass(), not(containsString("v-disabled"))); + + clickButton("Set readonly"); + + assertThat(getUploadButtonClass(), containsString("v-disabled")); + } + + @Test + public void buttonIsDisabled() { + assertThat(getUploadButtonClass(), not(containsString("v-disabled"))); + + clickButton("Set disabled"); + + assertThat(getUploadButtonClass(), containsString("v-disabled")); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidth.java b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidth.java new file mode 100644 index 0000000000..48dd96bc43 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidth.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.upload; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Upload; +import com.vaadin.ui.VerticalLayout; + +// We're explicitly testing only immediate uploads here because non-immediate +// width issues still require planning before we can provide a fix. +public class UploadImmediateButtonWidth extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + + // Let's use a separate layout without margins to make the + // button widths not dependent on the selected theme. + VerticalLayout layout = new VerticalLayout(); + layout.setWidth("500px"); + + layout.addComponent(getImmediateUpload("upload1", "300px")); + layout.addComponent(getImmediateUpload("upload2", "50%")); + layout.addComponent(getImmediateUpload("upload3", "")); + + addComponent(layout); + } + + private Upload getImmediateUpload(String id, String width) { + Upload upload = new Upload(); + + upload.setId(id); + upload.setWidth(width); + upload.setImmediate(true); + + return upload; + } + + @Override + protected String getTestDescription() { + return "Width of the upload button should obey setWidth() when using immediate"; + } + + @Override + protected Integer getTicketNumber() { + return 14485; + } + +} diff --git a/client/src/com/vaadin/client/ui/VPopupImplMozilla.java b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthChameleonTest.java index c9ede541ab..a0d6d471fb 100644 --- a/client/src/com/vaadin/client/ui/VPopupImplMozilla.java +++ b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthChameleonTest.java @@ -13,23 +13,24 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.client.ui; +package com.vaadin.tests.components.upload; -import com.google.gwt.dom.client.Element; -import com.google.gwt.user.client.ui.impl.PopupImplMozilla; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; -public class VPopupImplMozilla extends PopupImplMozilla { +import com.vaadin.ui.themes.*; +import org.junit.Test; - @Override - public void onShow(Element popup) { - // Move the overlay to the appropriate overlay container - final VOverlay overlay = VOverlay.current; - if (overlay != null) { - final Element e = overlay.getOverlayContainer(); - e.appendChild(popup); - } +public class UploadImmediateButtonWidthChameleonTest extends + UploadImmediateButtonWidthTest { - super.onShow(popup); + @Override + protected String getTheme() { + return ChameleonTheme.THEME_NAME; } + @Test + public void immediateButtonWithUndefinedWidth() { + assertThat(getButtonWidth("upload3"), closeTo(69, 4)); + } } diff --git a/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthReindeerTest.java b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthReindeerTest.java new file mode 100644 index 0000000000..c22e416a25 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthReindeerTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.upload; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; + +import com.vaadin.ui.themes.*; +import org.junit.Test; + +public class UploadImmediateButtonWidthReindeerTest extends + UploadImmediateButtonWidthTest { + + @Override + protected String getTheme() { + return Reindeer.THEME_NAME; + } + + @Test + public void immediateButtonWithUndefinedWidth() { + assertThat(getButtonWidth("upload3"), closeTo(67, 8)); + } +}
\ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/VPopupImpl.java b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthRunoTest.java index 5da54b248c..0ab4fbbc7e 100644 --- a/client/src/com/vaadin/client/ui/VPopupImpl.java +++ b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthRunoTest.java @@ -13,23 +13,24 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.client.ui; +package com.vaadin.tests.components.upload; -import com.google.gwt.dom.client.Element; -import com.google.gwt.user.client.ui.impl.PopupImpl; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; -public class VPopupImpl extends PopupImpl { +import com.vaadin.ui.themes.*; +import org.junit.Test; - @Override - public void onShow(Element popup) { - // Move the overlay to the appropriate overlay container - final VOverlay overlay = VOverlay.current; - if (overlay != null) { - final Element e = overlay.getOverlayContainer(); - e.appendChild(popup); - } +public class UploadImmediateButtonWidthRunoTest extends + UploadImmediateButtonWidthTest { - super.onShow(popup); + @Override + protected String getTheme() { + return Runo.THEME_NAME; } + @Test + public void immediateButtonWithUndefinedWidth() { + assertThat(getButtonWidth("upload3"), closeTo(72, 6)); + } } diff --git a/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthTest.java b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthTest.java new file mode 100644 index 0000000000..b2a29c92e3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.upload; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public abstract class UploadImmediateButtonWidthTest extends MultiBrowserTest { + + protected abstract String getTheme(); + + protected double getButtonWidth(String id) { + WebElement upload = driver.findElement(By.id(id)); + WebElement button = upload.findElement(By.className("v-button")); + + return button.getSize().getWidth(); + } + + @Override + protected Class<?> getUIClass() { + return UploadImmediateButtonWidth.class; + } + + @Override + public void setup() throws Exception { + super.setup(); + + openTestURL(String.format("theme=%s", getTheme())); + } + + @Test + public void immediateButtonWithPixelWidth() { + assertThat(getButtonWidth("upload1"), is(300.0)); + } + + @Test + public void immediateButtonWithPercentageWidth() { + assertThat(getButtonWidth("upload2"), is(250.0)); + } +} diff --git a/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthValoTest.java b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthValoTest.java new file mode 100644 index 0000000000..9d8fe6ba9e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/upload/UploadImmediateButtonWidthValoTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.upload; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; + +import com.vaadin.ui.themes.*; +import org.junit.Test; + +public class UploadImmediateButtonWidthValoTest extends + UploadImmediateButtonWidthTest { + + @Override + protected String getTheme() { + return ValoTheme.THEME_NAME; + } + + @Test + public void immediateButtonWithUndefinedWidth() { + assertThat(getButtonWidth("upload3"), closeTo(89, 2)); + } +} diff --git a/uitest/src/com/vaadin/tests/layouts/layouttester/BaseAddReplaceMoveTest.java b/uitest/src/com/vaadin/tests/layouts/layouttester/BaseAddReplaceMoveTest.java index 73dc39009d..786e47cef1 100644 --- a/uitest/src/com/vaadin/tests/layouts/layouttester/BaseAddReplaceMoveTest.java +++ b/uitest/src/com/vaadin/tests/layouts/layouttester/BaseAddReplaceMoveTest.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.List; import org.junit.Test; +import org.openqa.selenium.By; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.tests.tb3.MultiBrowserTest; @@ -27,7 +28,7 @@ public abstract class BaseAddReplaceMoveTest extends MultiBrowserTest { @Test public void LayoutAlignment() throws IOException, InterruptedException { openTestURL(); - sleep(500); + waitForElementPresent(By.className("v-table")); compareScreen("initial"); String[] states = { "add", "replace", "move", "remove" }; List<ButtonElement> buttons = $(ButtonElement.class).all(); @@ -35,7 +36,7 @@ public abstract class BaseAddReplaceMoveTest extends MultiBrowserTest { // go through all buttons click them and see result for (ButtonElement btn : buttons) { btn.click(); - sleep(500); + waitForElementPresent(By.className("v-table")); compareScreen(states[index]); index++; } diff --git a/uitest/src/com/vaadin/tests/layouts/layouttester/BaseLayoutExpandTest.java b/uitest/src/com/vaadin/tests/layouts/layouttester/BaseLayoutExpandTest.java index 08f5aed808..036b053fb5 100644 --- a/uitest/src/com/vaadin/tests/layouts/layouttester/BaseLayoutExpandTest.java +++ b/uitest/src/com/vaadin/tests/layouts/layouttester/BaseLayoutExpandTest.java @@ -19,21 +19,17 @@ import java.io.IOException; import java.util.List; import org.junit.Test; +import org.openqa.selenium.By; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.tests.tb3.MultiBrowserTest; -/** - * - * @since - * @author Vaadin Ltd - */ public abstract class BaseLayoutExpandTest extends MultiBrowserTest { @Test public void LayoutExpand() throws IOException, InterruptedException { openTestURL(); - sleep(500); + waitForElementPresent(By.className("v-table")); compareScreen("initial"); String[] states = { "expand_100_0", "expand_50_50", "expand_25_75" }; List<ButtonElement> buttons = $(ButtonElement.class).all(); @@ -41,7 +37,7 @@ public abstract class BaseLayoutExpandTest extends MultiBrowserTest { // go through all buttons click them and see result for (ButtonElement btn : buttons) { btn.click(); - sleep(500); + waitForElementPresent(By.className("v-table")); compareScreen(states[index]); index++; } diff --git a/uitest/src/com/vaadin/tests/push/BarInUIDL.java b/uitest/src/com/vaadin/tests/push/BarInUIDL.java index b380edcb75..a5d23dcd1f 100644 --- a/uitest/src/com/vaadin/tests/push/BarInUIDL.java +++ b/uitest/src/com/vaadin/tests/push/BarInUIDL.java @@ -35,14 +35,12 @@ public class BarInUIDL extends AbstractTestUI { */ @Override protected void setup(VaadinRequest request) { - Button button = new Button("Click Me"); - button.addClickListener(new Button.ClickListener() { + addButton("Click Me", new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { addComponent(new Label("Thank you for clicking | bar")); } }); - addComponent(button); } diff --git a/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java b/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java index 093ee348b8..cd779a7318 100644 --- a/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java @@ -24,6 +24,6 @@ import com.vaadin.tests.tb3.WebsocketTest; public class BasicPushWebsocketTest extends BasicPushTest { @Override public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); + return getBrowsersSupportingWebSocket(); } } diff --git a/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java b/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java index c0b188bbab..54775d572d 100644 --- a/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java @@ -26,6 +26,6 @@ public class ExtremelyLongPushTimeWebsocketTest extends @Override public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); + return getBrowsersSupportingWebSocket(); } } diff --git a/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java b/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java index 644dbd7580..7559d22264 100644 --- a/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java @@ -30,6 +30,6 @@ public class IdlePushChannelWebsocketTest extends IdlePushChannelTest { @Override public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); + return getBrowsersSupportingWebSocket(); } } diff --git a/uitest/src/com/vaadin/tests/push/PushWithPreserveOnRefresh.java b/uitest/src/com/vaadin/tests/push/PushWithPreserveOnRefresh.java index 8834a05069..af19f8849f 100644 --- a/uitest/src/com/vaadin/tests/push/PushWithPreserveOnRefresh.java +++ b/uitest/src/com/vaadin/tests/push/PushWithPreserveOnRefresh.java @@ -5,7 +5,6 @@ import com.vaadin.annotations.Push; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; 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.Label; @@ -24,16 +23,13 @@ public class PushWithPreserveOnRefresh extends AbstractTestUI { addComponent(new Label("UI id: " + getUIId())); addComponent(log); - Button b = new Button("click me"); - b.addClickListener(new ClickListener() { + addButton("click me", new ClickListener() { @Override public void buttonClick(ClickEvent event) { log.log("Button has been clicked " + (++times) + " times"); } }); - - addComponent(b); } @Override diff --git a/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java b/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java index efaf5d493e..bad00eba47 100644 --- a/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java @@ -25,7 +25,7 @@ public class ReconnectWebsocketTest extends ReconnectTest { @Override public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); + return getBrowsersSupportingWebSocket(); } @Override diff --git a/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java b/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java index ef461ab0da..42babb00d0 100644 --- a/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java +++ b/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java @@ -42,6 +42,6 @@ public class RefreshCloseConnectionTest extends MultiBrowserTest { @Override public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); + return getBrowsersSupportingWebSocket(); } } diff --git a/uitest/src/com/vaadin/tests/push/SendMultibyteCharacters.java b/uitest/src/com/vaadin/tests/push/SendMultibyteCharacters.java new file mode 100644 index 0000000000..e41f769724 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/SendMultibyteCharacters.java @@ -0,0 +1,23 @@ +package com.vaadin.tests.push; + +import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.TextArea; + +@Push +public class SendMultibyteCharacters extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + TextArea textArea = new TextArea(); + textArea.setImmediate(true); + + addComponent(textArea); + } + + @Override + protected Integer getTicketNumber() { + return 14674; + } +} diff --git a/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersLongPollingTest.java b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersLongPollingTest.java new file mode 100644 index 0000000000..fd89982253 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersLongPollingTest.java @@ -0,0 +1,9 @@ +package com.vaadin.tests.push; + +public class SendMultibyteCharactersLongPollingTest extends SendMultibyteCharactersTest { + + @Override + protected String getTransport() { + return "long-polling"; + } +} diff --git a/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersStreamingTest.java b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersStreamingTest.java new file mode 100644 index 0000000000..7b9ec38487 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersStreamingTest.java @@ -0,0 +1,9 @@ +package com.vaadin.tests.push; + +public class SendMultibyteCharactersStreamingTest extends SendMultibyteCharactersTest { + + @Override + protected String getTransport() { + return "streaming"; + } +} diff --git a/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersTest.java b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersTest.java new file mode 100644 index 0000000000..1ced2fb506 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersTest.java @@ -0,0 +1,42 @@ +package com.vaadin.tests.push; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.TextAreaElement; +import com.vaadin.tests.annotations.TestCategory; +import com.vaadin.tests.tb3.MultiBrowserTest; +import org.junit.Test; + +@TestCategory("push") +public abstract class SendMultibyteCharactersTest extends MultiBrowserTest { + + @Override + protected Class<?> getUIClass() { + return SendMultibyteCharacters.class; + } + + protected abstract String getTransport(); + + @Test + public void transportSupportsMultibyteCharacters() { + setDebug(true); + openTestURL("transport=" + getTransport()); + openDebugLogTab(); + + TextAreaElement textArea = $(TextAreaElement.class).first(); + + StringBuilder text = new StringBuilder(); + for(int i=0;i < 20;i++) { + text.append("之は日本語です、テストです。"); + } + + textArea.sendKeys(text.toString()); + + clearDebugMessages(); + + findElement(By.tagName("body")).click(); + + waitForDebugMessage("Variable burst to be sent to server:", 5); + waitForDebugMessage("Handling message from server", 10); + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersWebSocketTest.java b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersWebSocketTest.java new file mode 100644 index 0000000000..f37fb2efcb --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/SendMultibyteCharactersWebSocketTest.java @@ -0,0 +1,19 @@ +package com.vaadin.tests.push; + + +import org.openqa.selenium.remote.DesiredCapabilities; + +import java.util.List; + +public class SendMultibyteCharactersWebSocketTest extends SendMultibyteCharactersTest { + + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + return getBrowsersSupportingWebSocket(); + } + + @Override + protected String getTransport() { + return "websocket"; + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/AffectedTB3TestLocator.java b/uitest/src/com/vaadin/tests/tb3/AffectedTB3TestLocator.java new file mode 100644 index 0000000000..a3bee26675 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/AffectedTB3TestLocator.java @@ -0,0 +1,97 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tb3; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class AffectedTB3TestLocator extends TB3TestLocator { + + private final ChangedTB3TestLocator changedTB3TestLocator; + + public AffectedTB3TestLocator() { + changedTB3TestLocator = new ChangedTB3TestLocator(); + } + + @Override + protected <T> List<Class<? extends T>> findClasses(Class<T> baseClass, + String basePackage, String[] ignoredPackages) throws IOException { + List<Class<? extends T>> allTestClasses = super.findClasses(baseClass, + basePackage, ignoredPackages); + + List<Class<? extends T>> changedTestClasses = changedTB3TestLocator + .findClasses(baseClass, basePackage, ignoredPackages); + + return getAffectedTestClasses(allTestClasses, changedTestClasses); + } + + private <T> List<Class<? extends T>> getAffectedTestClasses( + List<Class<? extends T>> allTestClasses, + List<Class<? extends T>> changedTestClasses) throws IOException { + List<Class<? extends T>> affectedWithPackageTestClasses = getTestClassesWithAffectedPackageName(allTestClasses); + List<Class<? extends T>> affectedTestClasses = new ArrayList<Class<? extends T>>(); + affectedTestClasses.addAll(affectedWithPackageTestClasses); + + // Removing duplicate entries before adding changed test classes. + for (Class<? extends T> changedTestClass : changedTestClasses) { + for (Class<? extends T> affectedTestClass : affectedWithPackageTestClasses) { + if (!changedTestClass.getName().equals( + affectedTestClass.getName())) { + affectedTestClasses.add(changedTestClass); + + break; + } + } + } + return affectedTestClasses; + } + + private <T> List<Class<? extends T>> getTestClassesWithAffectedPackageName( + List<Class<? extends T>> classes) { + List<Class<? extends T>> affectedTestClasses = new ArrayList<Class<? extends T>>(); + List<String> affectedFiles = getAffectedFiles(); + + for (Class c : classes) { + String[] packageParts = c.getName().split("\\."); + String lastPart = packageParts[packageParts.length - 2]; + + for (String f : affectedFiles) { + if (f.toLowerCase().contains(lastPart.toLowerCase())) { + affectedTestClasses.add(c); + + // Break here not to accidentally add the same test class + // multiple times if it matches more than one file. + break; + } + } + } + + return affectedTestClasses; + } + + private List<String> getAffectedFiles() { + List<String> affectedFilePaths = new ArrayList<String>(); + + for (String path : changedTB3TestLocator.getChangedFilePaths()) { + if (!path.toLowerCase().contains("test")) { + affectedFilePaths.add(path); + } + } + + return affectedFilePaths; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/AffectedTB3Tests.java b/uitest/src/com/vaadin/tests/tb3/AffectedTB3Tests.java new file mode 100644 index 0000000000..6736bc3990 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/AffectedTB3Tests.java @@ -0,0 +1,27 @@ +package com.vaadin.tests.tb3; + +import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; + +import com.vaadin.tests.tb3.AffectedTB3Tests.AffectedTB3TestSuite; + +/** + * Test suite that runs tests from test classes which have changes or have + * similar package name compare the the changes files in the current workspace. + * If there are no changes in the workspace, it will run the changes to test + * classes introduced in the HEAD commit. + * + * @author Vaadin Ltd + */ +@RunWith(AffectedTB3TestSuite.class) +public class AffectedTB3Tests { + + public static class AffectedTB3TestSuite extends TB3TestSuite { + + public AffectedTB3TestSuite(Class<?> klass) throws InitializationError { + super(klass, AbstractTB3Test.class, "com.vaadin.tests", + new String[] { "com.vaadin.tests.integration" }, + new AffectedTB3TestLocator()); + } + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/ChangedTB3TestLocator.java b/uitest/src/com/vaadin/tests/tb3/ChangedTB3TestLocator.java new file mode 100644 index 0000000000..b425de48b5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/ChangedTB3TestLocator.java @@ -0,0 +1,158 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tb3; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.api.DiffCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.diff.DiffEntry.ChangeType; +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.diff.RawTextComparator; +import org.eclipse.jgit.errors.AmbiguousObjectException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.util.io.DisabledOutputStream; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class ChangedTB3TestLocator extends TB3TestLocator { + + @Override + protected <T> List<Class<? extends T>> findClasses(Class<T> baseClass, + String basePackage, String[] ignoredPackages) throws IOException { + + return getChangedTestClasses(baseClass); + } + + protected List<String> getChangedFilePaths() { + List<String> filePaths = new ArrayList<String>(); + + for (DiffEntry diff : getDiffs()) { + if (diff.getChangeType() != ChangeType.DELETE) { + filePaths.add(diff.getNewPath()); + System.out.println("Using changed file: " + diff.getNewPath()); + } + } + + return filePaths; + } + + private List<DiffEntry> getDiffs() { + try { + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + Repository repository = builder.setWorkTree(new File(".")) + .readEnvironment() // scan environment GIT_* variables + .findGitDir() // scan up the file system tree + .build(); + + List<DiffEntry> diffsInWorkingTree = getDiffsInWorkingTree(repository); + + if (diffsInWorkingTree.isEmpty()) { + return getDiffsInHead(repository); + } + + return diffsInWorkingTree; + + } catch (IOException e) { + e.printStackTrace(); + } catch (NoWorkTreeException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (GitAPIException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + private List<DiffEntry> getDiffsInWorkingTree(Repository repository) + throws GitAPIException { + Git git = new Git(repository); + DiffCommand diffCommand = git.diff(); + + List<DiffEntry> diffsInWorkingTree = new ArrayList<DiffEntry>(); + + for (DiffEntry diff : diffCommand.call()) { + // Exclude temporary junit files. + if (!diff.getNewPath().startsWith("uitest/junit")) { + diffsInWorkingTree.add(diff); + } + } + + return diffsInWorkingTree; + } + + private List<DiffEntry> getDiffsInHead(Repository repository) + throws AmbiguousObjectException, IncorrectObjectTypeException, + IOException, MissingObjectException { + RevWalk rw = new RevWalk(repository); + ObjectId head = repository.resolve(Constants.HEAD); + RevCommit commit = rw.parseCommit(head); + RevCommit parent = rw.parseCommit(commit.getParent(0).getId()); + DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE); + df.setRepository(repository); + df.setDiffComparator(RawTextComparator.DEFAULT); + df.setDetectRenames(true); + List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree()); + + return diffs; + } + + private <T> List<Class<? extends T>> getChangedTestClasses( + Class<T> baseClass) { + List<String> changedTestFilePaths = getTestFilePaths(); + List<Class<? extends T>> testClasses = new ArrayList<Class<? extends T>>(); + + for (String filePath : changedTestFilePaths) { + String path = filePath.replace("uitest/src/", "").replace(".java", + ""); + String className = path.replace("/", "."); + addClassIfMatches(testClasses, className, baseClass); + } + + return testClasses; + } + + private List<String> getTestFilePaths() { + List<String> changedTestFilePaths = new ArrayList<String>(); + + for (String filePath : getChangedFilePaths()) { + if (filePath.toLowerCase().startsWith("uitest") + && filePath.toLowerCase().endsWith(".java")) { + changedTestFilePaths.add(filePath); + } + } + + return changedTestFilePaths; + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/ChangedTB3Tests.java b/uitest/src/com/vaadin/tests/tb3/ChangedTB3Tests.java new file mode 100644 index 0000000000..2200566b84 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/ChangedTB3Tests.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tb3; + +import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; + +import com.vaadin.tests.tb3.ChangedTB3Tests.ChangedTB3TestsSuite; + +/** + * Test suite that runs tests from test classes which have changes in the + * current workspace. If there are no changes in the workspace, it will run the + * changes to test classes introduced in the HEAD commit. + * + * @since + * @author Vaadin Ltd + */ +@RunWith(ChangedTB3TestsSuite.class) +public class ChangedTB3Tests { + public static class ChangedTB3TestsSuite extends TB3TestSuite { + public ChangedTB3TestsSuite(Class<?> klass) throws InitializationError { + super(klass, AbstractTB3Test.class, "com.vaadin.tests", + new String[] { "com.vaadin.tests.integration" }, + new ChangedTB3TestLocator()); + + } + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java index d6eed3e5c8..ebcb02002e 100644 --- a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java +++ b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java @@ -40,6 +40,16 @@ import org.openqa.selenium.remote.DesiredCapabilities; */ public abstract class MultiBrowserTest extends PrivateTB3Configuration { + protected List<DesiredCapabilities> getBrowsersSupportingWebSocket() { + List<DesiredCapabilities> browsers = new ArrayList<DesiredCapabilities>(getAllBrowsers()); + + browsers.remove(Browser.IE8.getDesiredCapabilities()); + browsers.remove(Browser.IE9.getDesiredCapabilities()); + browsers.remove(Browser.PHANTOMJS.getDesiredCapabilities()); + + return browsers; + } + protected List<DesiredCapabilities> getBrowsersExcludingPhantomJS() { List<DesiredCapabilities> browsers = new ArrayList<DesiredCapabilities>(getAllBrowsers()); diff --git a/uitest/src/com/vaadin/tests/tb3/TB3TestLocator.java b/uitest/src/com/vaadin/tests/tb3/TB3TestLocator.java new file mode 100644 index 0000000000..a0fbf51195 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/TB3TestLocator.java @@ -0,0 +1,218 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tb3; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.net.JarURLConnection; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; + +public class TB3TestLocator { + /** + * Traverses the directory on the classpath (inside or outside a Jar file) + * specified by 'basePackage'. Collects all classes inside the location + * which can be assigned to 'baseClass' except for classes inside packages + * listed in 'ignoredPackages'. + * + * @param baseClass + * @param basePackage + * @param ignorePackages + * @return + */ + public Class<?>[] findTests(Class<? extends AbstractTB3Test> baseClass, + String basePackage, String[] ignorePackages) { + try { + List<?> l = findClasses(baseClass, basePackage, ignorePackages); + return l.toArray(new Class[] {}); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + /** + * Traverses the directory on the classpath (inside or outside a Jar file) + * specified by 'basePackage'. Collects all classes inside the location + * which can be assigned to 'baseClass' except for classes inside packages + * listed in 'ignoredPackages'. + * + * @param baseClass + * @param basePackage + * @param ignoredPackages + * @return + * @throws IOException + */ + protected <T> List<Class<? extends T>> findClasses(Class<T> baseClass, + String basePackage, String[] ignoredPackages) throws IOException { + List<Class<? extends T>> classes = new ArrayList<Class<? extends T>>(); + String basePackageDirName = "/" + basePackage.replace('.', '/'); + URL location = baseClass.getResource(basePackageDirName); + if (location.getProtocol().equals("file")) { + try { + File f = new File(location.toURI()); + if (!f.exists()) { + throw new IOException("Directory " + f.toString() + + " does not exist"); + } + findPackages(f, basePackage, baseClass, classes, + ignoredPackages); + } catch (URISyntaxException e) { + throw new IOException(e.getMessage()); + } + } else if (location.getProtocol().equals("jar")) { + JarURLConnection juc = (JarURLConnection) location.openConnection(); + findClassesInJar(juc, basePackage, baseClass, classes); + } + + Collections.sort(classes, new Comparator<Class<? extends T>>() { + + @Override + public int compare(Class<? extends T> o1, Class<? extends T> o2) { + return o1.getName().compareTo(o2.getName()); + } + + }); + + return classes; + } + + /** + * Traverses the given directory and collects all classes which are inside + * the given 'javaPackage' and can be assigned to the given 'baseClass'. The + * found classes are added to 'result'. + * + * @param parent + * The directory to traverse + * @param javaPackage + * The java package which 'parent' contains + * @param baseClass + * The class which the target classes extend + * @param result + * The collection to which found classes are added + * @param ignoredPackages + * A collection of packages (including sub packages) to ignore + */ + private <T> void findPackages(File parent, String javaPackage, + Class<T> baseClass, Collection<Class<? extends T>> result, + String[] ignoredPackages) { + for (String ignoredPackage : ignoredPackages) { + if (javaPackage.equals(ignoredPackage)) { + return; + } + } + + for (File file : parent.listFiles()) { + if (file.isDirectory()) { + findPackages(file, javaPackage + "." + file.getName(), + baseClass, result, ignoredPackages); + } else if (file.getName().endsWith(".class")) { + String fullyQualifiedClassName = javaPackage + "." + + file.getName().replace(".class", ""); + addClassIfMatches(result, fullyQualifiedClassName, baseClass); + } + } + + } + + /** + * Traverses a Jar file using the given connection and collects all classes + * which are inside the given 'javaPackage' and can be assigned to the given + * 'baseClass'. The found classes are added to 'result'. + * + * @param javaPackage + * The java package containing the classes (classes may be in a + * sub package) + * @param baseClass + * The class which the target classes extend + * @param result + * The collection to which found classes are added + * @throws IOException + */ + private <T> void findClassesInJar(JarURLConnection juc, String javaPackage, + Class<T> baseClass, Collection<Class<? extends T>> result) + throws IOException { + String javaPackageDir = javaPackage.replace('.', '/'); + Enumeration<JarEntry> ent = juc.getJarFile().entries(); + while (ent.hasMoreElements()) { + JarEntry e = ent.nextElement(); + if (e.getName().endsWith(".class") + && e.getName().startsWith(javaPackageDir)) { + String fullyQualifiedClassName = e.getName().replace('/', '.') + .replace(".class", ""); + addClassIfMatches(result, fullyQualifiedClassName, baseClass); + } + } + } + + /** + * Verifies that the class represented by 'fullyQualifiedClassName' can be + * loaded, assigned to 'baseClass' and is not an abstract or anonymous + * class. + * + * @param result + * The collection to add to + * @param fullyQualifiedClassName + * The candidate class + * @param baseClass + * The class 'fullyQualifiedClassName' should be assignable to + */ + @SuppressWarnings("unchecked") + protected <T> void addClassIfMatches(Collection<Class<? extends T>> result, + String fullyQualifiedClassName, Class<T> baseClass) { + try { + // Try to load the class + + Class<?> c = Class.forName(fullyQualifiedClassName); + if (!baseClass.isAssignableFrom(c)) { + return; + } + if (!includeInSuite(c)) { + return; + } + + if (!Modifier.isAbstract(c.getModifiers()) && !c.isAnonymousClass()) { + result.add((Class<? extends T>) c); + } + } catch (Exception e) { + // Could ignore that class cannot be loaded + e.printStackTrace(); + } catch (LinkageError e) { + // Ignore. Client side classes will at least throw LinkageErrors + } + + } + + /** + * @return true if the class should be included in the suite, false if not + */ + private boolean includeInSuite(Class<?> c) { + if (c.getAnnotation(ExcludeFromSuite.class) != null) { + return false; + } + + return true; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java b/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java index 703d01c122..b0554ce0f6 100644 --- a/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java +++ b/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java @@ -16,21 +16,8 @@ package com.vaadin.tests.tb3; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.net.JarURLConnection; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.jar.JarEntry; import org.junit.runners.Suite; import org.junit.runners.model.InitializationError; @@ -59,194 +46,16 @@ public class TB3TestSuite extends Suite { public TB3TestSuite(Class<?> klass, Class<? extends AbstractTB3Test> baseClass, String basePackage, String[] ignorePackages) throws InitializationError { - super(klass, findTests(baseClass, basePackage, ignorePackages)); - setScheduler(new ParallelScheduler(service)); + this(klass, baseClass, basePackage, ignorePackages, + new TB3TestLocator()); } - /** - * Traverses the directory on the classpath (inside or outside a Jar file) - * specified by 'basePackage'. Collects all classes inside the location - * which can be assigned to 'baseClass' except for classes inside packages - * listed in 'ignoredPackages'. - * - * @param baseClass - * @param basePackage - * @param ignorePackages - * @return - */ - private static Class<?>[] findTests( + public TB3TestSuite(Class<?> klass, Class<? extends AbstractTB3Test> baseClass, String basePackage, - String[] ignorePackages) { - try { - List<?> l = findClasses(baseClass, basePackage, ignorePackages); - return l.toArray(new Class[] {}); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - - /** - * Traverses the directory on the classpath (inside or outside a Jar file) - * specified by 'basePackage'. Collects all classes inside the location - * which can be assigned to 'baseClass' except for classes inside packages - * listed in 'ignoredPackages'. - * - * @param baseClass - * @param basePackage - * @param ignoredPackages - * @return - * @throws IOException - */ - private static <T> List<Class<? extends T>> findClasses(Class<T> baseClass, - String basePackage, String[] ignoredPackages) throws IOException { - List<Class<? extends T>> classes = new ArrayList<Class<? extends T>>(); - String basePackageDirName = "/" + basePackage.replace('.', '/'); - URL location = baseClass.getResource(basePackageDirName); - if (location.getProtocol().equals("file")) { - try { - File f = new File(location.toURI()); - if (!f.exists()) { - throw new IOException("Directory " + f.toString() - + " does not exist"); - } - findPackages(f, basePackage, baseClass, classes, - ignoredPackages); - } catch (URISyntaxException e) { - throw new IOException(e.getMessage()); - } - } else if (location.getProtocol().equals("jar")) { - JarURLConnection juc = (JarURLConnection) location.openConnection(); - findClassesInJar(juc, basePackage, baseClass, classes); - } - - Collections.sort(classes, new Comparator<Class<? extends T>>() { - - @Override - public int compare(Class<? extends T> o1, Class<? extends T> o2) { - return o1.getName().compareTo(o2.getName()); - } - - }); - return classes; - } - - /** - * Traverses the given directory and collects all classes which are inside - * the given 'javaPackage' and can be assigned to the given 'baseClass'. The - * found classes are added to 'result'. - * - * @param parent - * The directory to traverse - * @param javaPackage - * The java package which 'parent' contains - * @param baseClass - * The class which the target classes extend - * @param result - * The collection to which found classes are added - * @param ignoredPackages - * A collection of packages (including sub packages) to ignore - */ - private static <T> void findPackages(File parent, String javaPackage, - Class<T> baseClass, Collection<Class<? extends T>> result, - String[] ignoredPackages) { - for (String ignoredPackage : ignoredPackages) { - if (javaPackage.equals(ignoredPackage)) { - return; - } - } - - for (File file : parent.listFiles()) { - if (file.isDirectory()) { - findPackages(file, javaPackage + "." + file.getName(), - baseClass, result, ignoredPackages); - } else if (file.getName().endsWith(".class")) { - String fullyQualifiedClassName = javaPackage + "." - + file.getName().replace(".class", ""); - addClassIfMatches(result, fullyQualifiedClassName, baseClass); - } - } - - } - - /** - * Traverses a Jar file using the given connection and collects all classes - * which are inside the given 'javaPackage' and can be assigned to the given - * 'baseClass'. The found classes are added to 'result'. - * - * @param javaPackage - * The java package containing the classes (classes may be in a - * sub package) - * @param baseClass - * The class which the target classes extend - * @param result - * The collection to which found classes are added - * @throws IOException - */ - private static <T> void findClassesInJar(JarURLConnection juc, - String javaPackage, Class<T> baseClass, - Collection<Class<? extends T>> result) throws IOException { - String javaPackageDir = javaPackage.replace('.', '/'); - Enumeration<JarEntry> ent = juc.getJarFile().entries(); - while (ent.hasMoreElements()) { - JarEntry e = ent.nextElement(); - if (e.getName().endsWith(".class") - && e.getName().startsWith(javaPackageDir)) { - String fullyQualifiedClassName = e.getName().replace('/', '.') - .replace(".class", ""); - addClassIfMatches(result, fullyQualifiedClassName, baseClass); - } - } - } - - /** - * Verifies that the class represented by 'fullyQualifiedClassName' can be - * loaded, assigned to 'baseClass' and is not an abstract or anonymous - * class. - * - * @param result - * The collection to add to - * @param fullyQualifiedClassName - * The candidate class - * @param baseClass - * The class 'fullyQualifiedClassName' should be assignable to - */ - @SuppressWarnings("unchecked") - private static <T> void addClassIfMatches( - Collection<Class<? extends T>> result, - String fullyQualifiedClassName, Class<T> baseClass) { - try { - // Try to load the class - - Class<?> c = Class.forName(fullyQualifiedClassName); - if (!baseClass.isAssignableFrom(c)) { - return; - } - if (!includeInSuite(c)) { - return; - } - - if (!Modifier.isAbstract(c.getModifiers()) && !c.isAnonymousClass()) { - result.add((Class<? extends T>) c); - } - } catch (Exception e) { - // Could ignore that class cannot be loaded - e.printStackTrace(); - } catch (LinkageError e) { - // Ignore. Client side classes will at least throw LinkageErrors - } - - } - - /** - * @return true if the class should be included in the suite, false if not - */ - private static boolean includeInSuite(Class<?> c) { - if (c.getAnnotation(ExcludeFromSuite.class) != null) { - return false; - } - - return true; + String[] ignorePackages, TB3TestLocator testLocator) + throws InitializationError { + super(klass, testLocator.findTests(baseClass, basePackage, + ignorePackages)); + setScheduler(new ParallelScheduler(service)); } } diff --git a/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java b/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java index 778c8b9113..ddcc6d5d76 100644 --- a/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java +++ b/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java @@ -35,30 +35,10 @@ import com.vaadin.tests.tb3.MultiBrowserTest.Browser; * @author Vaadin Ltd */ @TestCategory("push") -public abstract class WebsocketTest extends PrivateTB3Configuration { - private static List<DesiredCapabilities> websocketBrowsers = new ArrayList<DesiredCapabilities>(); - static { - websocketBrowsers.addAll(MultiBrowserTest.getAllBrowsers()); - websocketBrowsers.remove(Browser.IE8.getDesiredCapabilities()); - websocketBrowsers.remove(Browser.IE9.getDesiredCapabilities()); - websocketBrowsers.remove(Browser.PHANTOMJS.getDesiredCapabilities()); - } - - /** - * @return All supported browsers which are actively tested and support - * websockets - */ - public static List<DesiredCapabilities> getWebsocketBrowsers() { - return Collections.unmodifiableList(websocketBrowsers); - } +public abstract class WebsocketTest extends MultiBrowserTest { - /* - * (non-Javadoc) - * - * @see com.vaadin.tests.tb3.AbstractTB3Test#getBrowserToRunOn() - */ @Override public List<DesiredCapabilities> getBrowsersToTest() { - return new ArrayList<DesiredCapabilities>(getWebsocketBrowsers()); + return new ArrayList<DesiredCapabilities>(getBrowsersSupportingWebSocket()); } } diff --git a/uitest/src/com/vaadin/tests/themes/ThemeChangeOnTheFly.java b/uitest/src/com/vaadin/tests/themes/ThemeChangeOnTheFly.java index ec22edd205..0ea5c18bc9 100644 --- a/uitest/src/com/vaadin/tests/themes/ThemeChangeOnTheFly.java +++ b/uitest/src/com/vaadin/tests/themes/ThemeChangeOnTheFly.java @@ -36,8 +36,7 @@ public class ThemeChangeOnTheFly extends AbstractTestUIWithLog { @Override protected void setup(VaadinRequest request) { - Button inject = new Button("Inject blue background"); - inject.addClickListener(new ClickListener() { + addButton("Inject blue background", new ClickListener() { @Override public void buttonClick(ClickEvent event) { @@ -46,7 +45,6 @@ public class ThemeChangeOnTheFly extends AbstractTestUIWithLog { } }); - addComponent(inject); GridLayout gl = new GridLayout(2, 4); gl.setCaption("Change theme by clicking a button"); diff --git a/uitest/src/com/vaadin/tests/themes/valo/DateFields.java b/uitest/src/com/vaadin/tests/themes/valo/DateFields.java index 5a752cd985..4b29f83621 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/DateFields.java +++ b/uitest/src/com/vaadin/tests/themes/valo/DateFields.java @@ -203,6 +203,7 @@ public class DateFields extends VerticalLayout implements View { item.addItemProperty("date", new ObjectProperty<Date>(getDefaultDate())); FormLayout form = new FormLayout(); + form.setMargin(false); FieldGroup binder = new FieldGroup(item); form.addComponent(binder.buildAndBind( diff --git a/uitest/src/com/vaadin/tests/themes/valo/TableSortIndicator.java b/uitest/src/com/vaadin/tests/themes/valo/TableSortIndicator.java new file mode 100644 index 0000000000..74e5fcd0ef --- /dev/null +++ b/uitest/src/com/vaadin/tests/themes/valo/TableSortIndicator.java @@ -0,0 +1,34 @@ +package com.vaadin.tests.themes.valo; + +import com.vaadin.annotations.*; +import com.vaadin.server.*; +import com.vaadin.tests.components.*; +import com.vaadin.ui.*; + +@Theme("valo") +public class TableSortIndicator extends AbstractTestUI { + @Override + protected void setup(VaadinRequest request) { + Table table = new Table(); + table.addContainerProperty("Index", Integer.class, ""); + + for(int i=0;i<10;i++) { + table.addItem(new Object[] {i}, i); + } + + table.setPageLength(0); + + addComponent(table); + } + + @Override + protected String getTestDescription() { + return "For Valo, sorting indicators should point up when sorted asc " + + "and down when sorted desc."; + } + + @Override + protected Integer getTicketNumber() { + return 15123; + } +} diff --git a/uitest/src/com/vaadin/tests/themes/valo/TableSortIndicatorTest.java b/uitest/src/com/vaadin/tests/themes/valo/TableSortIndicatorTest.java new file mode 100644 index 0000000000..42f0b2aeae --- /dev/null +++ b/uitest/src/com/vaadin/tests/themes/valo/TableSortIndicatorTest.java @@ -0,0 +1,46 @@ +package com.vaadin.tests.themes.valo; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.*; +import org.junit.*; +import org.openqa.selenium.*; + +import java.io.*; + +public class TableSortIndicatorTest extends MultiBrowserTest { + + private void clickOnCellHeader() { + clickElementByClass("v-table-header-cell"); + } + + @Test + public void ascendingIndicatorIsShown() throws IOException { + openTestURL(); + + clickOnCellHeader(); + + compareScreen("ascending"); + } + + @Test + public void descendingIndicatorIsShown() throws IOException { + openTestURL(); + + clickOnCellHeader(); + clickOnSortIndicator(); + + compareScreen("descending"); + } + + private void clickOnSortIndicator() { + clickElementByClass("v-table-sort-indicator"); + } + + private void clickElementByClass(String className) { + findElementByClass(className).click(); + } + + private WebElement findElementByClass(String className) { + return driver.findElement(By.className(className)); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUITest.java b/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUITest.java index d4ddf2dcf9..92cb837b38 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUITest.java +++ b/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUITest.java @@ -133,6 +133,15 @@ public class ValoThemeUITest extends MultiBrowserTest { } @Test + public void treeTables() throws Exception { + openTestURL("test"); + open("Tables"); + check("Hierarchical"); + check("Footer"); + compareScreen("treetables"); + } + + @Test public void dragging() throws Exception { openTestURL("test"); open("Drag and Drop", "Dragging Components"); @@ -172,6 +181,17 @@ public class ValoThemeUITest extends MultiBrowserTest { } @Test + public void tabsClosableUnframed() throws Exception { + openTestURL("test"); + open("Tabs <span class=\"valo-menu-badge\">123</span>", "Tabs"); + check("Closable"); + // Framed option is checked by default so we are actually unchecking + check("Framed"); + check("Overflow"); + compareScreen("tabs-closable-unframed"); + } + + @Test public void tabsAlignRight() throws Exception { openTestURL("test"); open("Tabs <span class=\"valo-menu-badge\">123</span>", "Tabs"); diff --git a/uitest/src/com/vaadin/tests/tooltip/TooltipWidthUpdating.java b/uitest/src/com/vaadin/tests/tooltip/TooltipWidthUpdating.java new file mode 100644 index 0000000000..c5e49d1af3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/TooltipWidthUpdating.java @@ -0,0 +1,69 @@ +package com.vaadin.tests.tooltip; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.util.LoremIpsum; +import com.vaadin.ui.NativeButton; +import com.vaadin.ui.TextField; +import com.vaadin.ui.VerticalLayout; + +/** + * Test to see if the width of the tooltip element is updated if a narrower + * tooltip is opened to replace a tooltip with wider content. + * + * @author Vaadin Ltd + */ +public class TooltipWidthUpdating extends AbstractTestUI { + + private static final long serialVersionUID = 1L; + protected static final String SHORT_TOOLTIP_TEXT = "This is a short tooltip"; + protected static final String LONG_TOOLTIP_TEXT = LoremIpsum.get(5000); + protected static final Integer MAX_WIDTH = 500; + + @Override + protected void setup(VaadinRequest request) { + NativeButton componentWithShortTooltip = new NativeButton( + "Short tooltip"); + componentWithShortTooltip.setDescription(SHORT_TOOLTIP_TEXT); + componentWithShortTooltip.setId("shortTooltip"); + + getTooltipConfiguration().setMaxWidth(MAX_WIDTH); + getTooltipConfiguration().setCloseTimeout(200); + + NativeButton componentWithLongTooltip = new NativeButton("Long tooltip"); + componentWithLongTooltip.setId("longTooltip"); + componentWithLongTooltip.setDescription(LONG_TOOLTIP_TEXT); + + VerticalLayout vl = new VerticalLayout(); + + TextField component1 = new TextField("TextField"); + component1.setId("component1"); + TextField component2 = new TextField("TextField"); + TextField component3 = new TextField("TextField"); + TextField component4 = new TextField("TextField"); + TextField component5 = new TextField("TextField"); + TextField component6 = new TextField("TextField"); + TextField component7 = new TextField("TextField"); + TextField component8 = new TextField("TextField"); + + // some count of any components should be added before (between) buttons + // to make defect reproducible + vl.addComponents(component1, component2, component2, component3, + component4, component5, component5, component6, component7, + component8); + + getLayout().addComponents(componentWithShortTooltip, vl, + componentWithLongTooltip); + } + + @Override + protected String getTestDescription() { + return "Tests that tooltip element width is updated if a narrower tooltip is opened to replace a tooltip with wider content"; + } + + @Override + protected Integer getTicketNumber() { + return 11871; + } + +} diff --git a/uitest/src/com/vaadin/tests/tooltip/TooltipWidthUpdatingTest.java b/uitest/src/com/vaadin/tests/tooltip/TooltipWidthUpdatingTest.java new file mode 100644 index 0000000000..150d0e070e --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/TooltipWidthUpdatingTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.tooltip; + +import static org.hamcrest.Matchers.lessThan; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.TooltipTest; + +public class TooltipWidthUpdatingTest extends TooltipTest { + + @Test + public void testTooltipWidthUpdating() { + openTestURL(); + + WebElement btnLongTooltip = vaadinElementById("longTooltip"); + WebElement btnShortTooltip = vaadinElementById("shortTooltip"); + + moveMouseToTopLeft(btnLongTooltip); + testBenchElement(btnLongTooltip).showTooltip(); + + moveMouseToTopLeft(btnShortTooltip); + testBenchElement(btnShortTooltip).showTooltip(); + + assertThat(getDriver().findElement(By.className("popupContent")) + .getSize().getWidth(), lessThan(TooltipWidthUpdating.MAX_WIDTH)); + } + +}
\ No newline at end of file |