aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/VAADIN/themes/base/button/checkbox.scss4
-rw-r--r--WebContent/VAADIN/themes/base/grid/grid.scss24
-rw-r--r--WebContent/VAADIN/themes/chameleon/components/components.scss2
-rw-r--r--WebContent/VAADIN/themes/chameleon/components/grid/grid.scss12
-rw-r--r--WebContent/VAADIN/themes/reindeer/grid/grid.scss6
-rw-r--r--WebContent/VAADIN/themes/reindeer/reindeer.scss20
-rw-r--r--WebContent/VAADIN/themes/runo/grid/grid.scss15
-rw-r--r--WebContent/VAADIN/themes/runo/runo.scss22
-rw-r--r--WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt1
-rw-r--r--WebContent/VAADIN/themes/tests-tickets/ordinary.txt1
-rw-r--r--WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt1
-rw-r--r--WebContent/VAADIN/themes/valo/components/_grid.scss12
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss16
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss183
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss13
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss6
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss8
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss33
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss2
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss2
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss67
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss8
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss2
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss5
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_flex-box.scss28
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-face.scss2
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-feature-settings.scss10
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_image-rendering.scss1
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_keyframes.scss15
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_placeholder.scss27
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/css3/_transition.scss51
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss13
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss2
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss15
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss26
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss4
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss1
-rw-r--r--WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss10
-rw-r--r--WebContent/WEB-INF/web.xml15
-rw-r--r--WebContent/release-notes.html7
-rwxr-xr-xbuild/ide.xml2
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java6
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java6
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java111
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java16
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java10
-rw-r--r--client/src/com/vaadin/client/BrowserInfo.java16
-rw-r--r--client/src/com/vaadin/client/ComputedStyle.java84
-rw-r--r--client/src/com/vaadin/client/EventHelper.java17
-rw-r--r--client/src/com/vaadin/client/ResourceLoader.java8
-rw-r--r--client/src/com/vaadin/client/SuperDevMode.java6
-rw-r--r--client/src/com/vaadin/client/VTooltip.java3
-rw-r--r--client/src/com/vaadin/client/connectors/AbstractSelectionModelConnector.java82
-rw-r--r--client/src/com/vaadin/client/connectors/GridConnector.java780
-rw-r--r--client/src/com/vaadin/client/connectors/MultiSelectionModelConnector.java383
-rw-r--r--client/src/com/vaadin/client/connectors/NoSelectionModelConnector.java42
-rw-r--r--client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java58
-rw-r--r--client/src/com/vaadin/client/connectors/SingleSelectionModelConnector.java148
-rw-r--r--client/src/com/vaadin/client/data/AbstractRemoteDataSource.java61
-rw-r--r--client/src/com/vaadin/client/debug/internal/VDebugWindow.java38
-rw-r--r--client/src/com/vaadin/client/extensions/ResponsiveConnector.java6
-rw-r--r--client/src/com/vaadin/client/ui/AbstractConnector.java2
-rw-r--r--client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java87
-rw-r--r--client/src/com/vaadin/client/ui/FocusableScrollPanel.java2
-rw-r--r--client/src/com/vaadin/client/ui/VButton.java3
-rw-r--r--client/src/com/vaadin/client/ui/VFilterSelect.java46
-rw-r--r--client/src/com/vaadin/client/ui/VFormLayout.java17
-rw-r--r--client/src/com/vaadin/client/ui/VRichTextArea.java2
-rw-r--r--client/src/com/vaadin/client/ui/VScrollTable.java20
-rw-r--r--client/src/com/vaadin/client/ui/VTabsheet.java10
-rw-r--r--client/src/com/vaadin/client/ui/VTextArea.java8
-rw-r--r--client/src/com/vaadin/client/ui/VTree.java15
-rw-r--r--client/src/com/vaadin/client/ui/VUI.java10
-rw-r--r--client/src/com/vaadin/client/ui/VWindow.java42
-rw-r--r--client/src/com/vaadin/client/ui/button/ButtonConnector.java38
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java9
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java7
-rw-r--r--client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java34
-rw-r--r--client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java35
-rw-r--r--client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java44
-rw-r--r--client/src/com/vaadin/client/ui/tree/TreeConnector.java6
-rw-r--r--client/src/com/vaadin/client/ui/ui/UIConnector.java88
-rw-r--r--client/src/com/vaadin/client/ui/window/WindowConnector.java14
-rw-r--r--client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java225
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java34
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorEvent.java108
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java49
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java34
-rw-r--r--client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java34
-rw-r--r--client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java4
-rw-r--r--client/src/com/vaadin/client/widgets/Escalator.java643
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java874
-rw-r--r--client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java25
-rw-r--r--eclipse/Super Development Mode (vaadin).launch2
-rw-r--r--push/ivy.xml2
-rw-r--r--scripts/DeployHelpers.py37
-rw-r--r--scripts/GenerateBuildReport.py13
-rw-r--r--scripts/GeneratePublishReport.py65
-rw-r--r--scripts/GenerateStagingReport.py49
-rw-r--r--server/build.xml2
-rw-r--r--server/ivy.xml2
-rw-r--r--server/src/com/vaadin/data/DataGenerator.java49
-rw-r--r--server/src/com/vaadin/data/RpcDataProviderExtension.java958
-rw-r--r--server/src/com/vaadin/data/util/ContainerOrderedWrapper.java24
-rw-r--r--server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java83
-rw-r--r--server/src/com/vaadin/event/ShortcutAction.java30
-rw-r--r--server/src/com/vaadin/server/Constants.java1
-rw-r--r--server/src/com/vaadin/server/VaadinServlet.java20
-rw-r--r--server/src/com/vaadin/server/WebBrowser.java14
-rw-r--r--server/src/com/vaadin/server/communication/AtmospherePushConnection.java37
-rw-r--r--server/src/com/vaadin/server/communication/FileUploadHandler.java2
-rw-r--r--server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java9
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java41
-rw-r--r--server/src/com/vaadin/server/communication/PushRequestHandler.java25
-rw-r--r--server/src/com/vaadin/ui/AbstractFocusable.java134
-rw-r--r--server/src/com/vaadin/ui/Button.java105
-rw-r--r--server/src/com/vaadin/ui/Grid.java924
-rw-r--r--server/src/com/vaadin/ui/HorizontalLayout.java7
-rw-r--r--server/src/com/vaadin/ui/Table.java90
-rw-r--r--server/src/com/vaadin/ui/VerticalLayout.java7
-rw-r--r--server/src/com/vaadin/ui/Window.java238
-rw-r--r--server/src/com/vaadin/ui/renderers/ImageRenderer.java2
-rw-r--r--server/src/com/vaadin/ui/themes/ValoTheme.java2
-rw-r--r--server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java153
-rw-r--r--server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java29
-rw-r--r--server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java20
-rw-r--r--server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java102
-rw-r--r--server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java27
-rw-r--r--server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java120
-rw-r--r--server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java34
-rw-r--r--server/tests/src/com/vaadin/tests/data/converter/StringToEnumConverterTest.java49
-rw-r--r--server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java4
-rw-r--r--server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/button/ButtonDeclarativeTest.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java88
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java39
-rw-r--r--server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java26
-rw-r--r--shared/src/com/vaadin/shared/VBrowserDetails.java25
-rw-r--r--shared/src/com/vaadin/shared/data/DataProviderRpc.java12
-rw-r--r--shared/src/com/vaadin/shared/data/DataRequestRpc.java18
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java17
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridConstants.java15
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java46
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/GridState.java43
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelServerRpc.java55
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelState.java31
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelServerRpc.java35
-rw-r--r--shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelState.java30
-rw-r--r--shared/src/com/vaadin/shared/ui/table/TableConstants.java1
-rw-r--r--uitest/integration_tests.xml3
-rw-r--r--uitest/ivy.xml2
-rw-r--r--uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java2
-rw-r--r--uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java10
-rw-r--r--uitest/src/com/vaadin/tests/components/AbstractComponentTest.java41
-rw-r--r--uitest/src/com/vaadin/tests/components/OutOfSync.java55
-rw-r--r--uitest/src/com/vaadin/tests/components/OutOfSyncTest.java89
-rw-r--r--uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java46
-rw-r--r--uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java11
-rw-r--r--uitest/src/com/vaadin/tests/components/button/Buttons2.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java14
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java15
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java15
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java30
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java58
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java40
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java60
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java40
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java4
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModel.java37
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModelTest.java58
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java24
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java19
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.java43
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java78
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java6
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java148
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.java73
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java49
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java43
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java41
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java243
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java6
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java74
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java55
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java20
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java37
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java43
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java264
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java296
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java223
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java79
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java58
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java12
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java12
-rw-r--r--uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java58
-rw-r--r--uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java75
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java64
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java112
-rw-r--r--uitest/src/com/vaadin/tests/components/table/CustomTableElement.java57
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java50
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java52
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java43
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java43
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java51
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java46
-rw-r--r--uitest/src/com/vaadin/tests/components/window/GridInWindow.java49
-rw-r--r--uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java36
-rw-r--r--uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java62
-rw-r--r--uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java48
-rw-r--r--uitest/src/com/vaadin/tests/components/window/WindowCloseShortcuts.java199
-rw-r--r--uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java33
-rw-r--r--uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java47
-rw-r--r--uitest/src/com/vaadin/tests/debug/ProfilerZeroOverhead.java37
-rw-r--r--uitest/src/com/vaadin/tests/debug/ProfilerZeroOverheadTest.java51
-rw-r--r--uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java14
-rw-r--r--uitest/src/com/vaadin/tests/integration/JSR286Portlet.java14
-rw-r--r--uitest/src/com/vaadin/tests/push/BasicPushLongPollingTest.java14
-rw-r--r--uitest/src/com/vaadin/tests/push/BasicPushTest.java8
-rw-r--r--uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java94
-rw-r--r--uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java54
-rw-r--r--uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java52
-rw-r--r--uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java92
-rw-r--r--uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java4
-rw-r--r--uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java10
-rw-r--r--uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java6
-rw-r--r--uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java16
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Accordions.java5
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java3
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java47
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java10
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java25
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java5
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java19
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/CommonParts.java79
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/DateFields.java19
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Dragging.java15
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Forms.java31
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Labels.java27
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/MenuBars.java31
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java5
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java4
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Panels.java29
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/PopupViews.java5
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Sliders.java15
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java9
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Tables.java51
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java9
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/TextFields.java73
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/Trees.java5
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java5
-rw-r--r--uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java26
-rw-r--r--uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java34
-rw-r--r--uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java46
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml3
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/ProfilerCompilationCanary.java48
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.java83
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/MySelectionModelConnector.java61
-rw-r--r--uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html38
-rw-r--r--uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html27
-rw-r--r--uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html152
-rw-r--r--uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html97
-rw-r--r--uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html16
266 files changed, 10286 insertions, 4189 deletions
diff --git a/WebContent/VAADIN/themes/base/button/checkbox.scss b/WebContent/VAADIN/themes/base/button/checkbox.scss
index cc6143dbc1..e46d236035 100644
--- a/WebContent/VAADIN/themes/base/button/checkbox.scss
+++ b/WebContent/VAADIN/themes/base/button/checkbox.scss
@@ -1,9 +1,5 @@
@mixin base-checkbox($primaryStyleName : v-checkbox) {
- .#{$primaryStyleName} {
- display: block;
- }
-
.#{$primaryStyleName},
.#{$primaryStyleName} label,
.#{$primaryStyleName} input,
diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss
index 1653032703..6b3b017070 100644
--- a/WebContent/VAADIN/themes/base/grid/grid.scss
+++ b/WebContent/VAADIN/themes/base/grid/grid.scss
@@ -108,6 +108,7 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co
outline: none;
padding: 0 4px;
text-align: right;
+ line-height: 1;
&::-moz-focus-inner {
border: 0;
@@ -128,10 +129,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co
&.open {
.#{$primaryStyleName}-sidebar-button {
width: 100%;
-
+
&:after {
- content: "\00d7";
- font-size: 16px;
+ content: "\f0c9";
+ font-size: $v-grid-header-font-size;
line-height: 1;
}
}
@@ -142,11 +143,12 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co
}
.v-ie8 &.open .#{$primaryStyleName}-sidebar-button:after {
+ vertical-align: middle;
+ text-align: center;
display: inline;
}
.#{$primaryStyleName}-sidebar-content {
- border-top: $v-grid-border;
padding: 4px 0;
.gwt-MenuBar {
@@ -199,6 +201,12 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co
border-left: none;
}
}
+
+ .#{$primaryStyleName}-editor-cells.frozen > div {
+ @include box-shadow(1px 0 2px rgba(0,0,0,.1));
+ border-right: $v-grid-cell-vertical-border;
+ border-left: none;
+ }
.#{$primaryStyleName}-row-stripe > td {
background-color: $v-grid-row-stripe-background-color;
@@ -342,6 +350,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co
.#{$primaryStyleName}-editor-cells {
position: relative;
white-space: nowrap;
+
+ &.frozen {
+ z-index: 2;
+ }
> div {
display: inline-block;
@@ -384,6 +396,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co
min-width: 100%;
max-width: 100%;
}
+
+ &.not-editable.#{$primaryStyleName}-cell {
+ float: none;
+ }
}
.error::before {
diff --git a/WebContent/VAADIN/themes/chameleon/components/components.scss b/WebContent/VAADIN/themes/chameleon/components/components.scss
index 9c8a56b33d..578ea23bf3 100644
--- a/WebContent/VAADIN/themes/chameleon/components/components.scss
+++ b/WebContent/VAADIN/themes/chameleon/components/components.scss
@@ -1,6 +1,7 @@
@import "accordion/accordion.scss";
@import "button/button.scss";
@import "colorpicker/colorpicker.scss";
+@import "grid/grid.scss";
@import "label/label.scss";
@import "menubar/menubar.scss";
@import "notification/notification.scss";
@@ -24,6 +25,7 @@
@include chameleon-accordion;
@include chameleon-button;
@include chameleon-colorpicker;
+ @include chameleon-grid;
@include chameleon-label;
@include chameleon-menubar;
@include chameleon-notification;
diff --git a/WebContent/VAADIN/themes/chameleon/components/grid/grid.scss b/WebContent/VAADIN/themes/chameleon/components/grid/grid.scss
new file mode 100644
index 0000000000..5007ad6619
--- /dev/null
+++ b/WebContent/VAADIN/themes/chameleon/components/grid/grid.scss
@@ -0,0 +1,12 @@
+@mixin chameleon-grid($primaryStyleName: v-grid) {
+
+ // Sidebar
+ .#{$primaryStyleName}-sidebar.v-contextmenu {
+
+ .v-on:before, .v-off:before {
+ content: none;
+ font-size: 0;
+ margin-right: 0;
+ }
+ }
+}
diff --git a/WebContent/VAADIN/themes/reindeer/grid/grid.scss b/WebContent/VAADIN/themes/reindeer/grid/grid.scss
index 7ae0f402aa..cb5e9d454e 100644
--- a/WebContent/VAADIN/themes/reindeer/grid/grid.scss
+++ b/WebContent/VAADIN/themes/reindeer/grid/grid.scss
@@ -40,6 +40,12 @@
.#{$primaryStyleName}-sidebar-content {
background-color: #f8f8f9;
}
+
+ .v-on:before, .v-off:before {
+ content: none;
+ font-size: 0;
+ margin-right: 0;
+ }
}
// Sort indicators
diff --git a/WebContent/VAADIN/themes/reindeer/reindeer.scss b/WebContent/VAADIN/themes/reindeer/reindeer.scss
index cda571fda0..fece9f1043 100644
--- a/WebContent/VAADIN/themes/reindeer/reindeer.scss
+++ b/WebContent/VAADIN/themes/reindeer/reindeer.scss
@@ -3,16 +3,16 @@ $line-height: normal !default;
// Override Base Grid variables
-$v-grid-border: 1px solid #c2c3c4;
-$v-grid-cell-vertical-border: 1px solid #d4d4d4;
-$v-grid-cell-horizontal-border: none;
-$v-grid-cell-focused-border: 1px solid #0f68ba;
-$v-grid-row-height: 20px;
-$v-grid-row-stripe-background-color: #eff0f1;
-$v-grid-row-selected-background-color: #4d749f;
-$v-grid-header-font-size: 10px;
-$v-grid-header-background-color: rgb(217,219,221);
-$v-grid-cell-padding-horizontal: 6px;
+$v-grid-border: 1px solid #c2c3c4 !default;
+$v-grid-cell-vertical-border: 1px solid #d4d4d4 !default;
+$v-grid-cell-horizontal-border: none !default;
+$v-grid-cell-focused-border: 1px solid #0f68ba !default;
+$v-grid-row-height: 20px !default;
+$v-grid-row-stripe-background-color: #eff0f1 !default;
+$v-grid-row-selected-background-color: #4d749f !default;
+$v-grid-header-font-size: 10px !default;
+$v-grid-header-background-color: rgb(217,219,221) !default;
+$v-grid-cell-padding-horizontal: 6px !default;
@import "../base/base.scss";
diff --git a/WebContent/VAADIN/themes/runo/grid/grid.scss b/WebContent/VAADIN/themes/runo/grid/grid.scss
index aca9821c53..1f049c5fb0 100644
--- a/WebContent/VAADIN/themes/runo/grid/grid.scss
+++ b/WebContent/VAADIN/themes/runo/grid/grid.scss
@@ -30,14 +30,7 @@
// Sidebar
.#{$primaryStyleName}-sidebar.v-contextmenu {
- &.open {
- .#{$primaryStyleName}-sidebar-button {
- &:after {
- font-size: 22px;
- }
- }
- }
-
+
.#{$primaryStyleName}-sidebar-content {
background-color: transparent;
@@ -45,6 +38,12 @@
border: none;
}
}
+
+ .v-on:before, .v-off:before {
+ content: none;
+ font-size: 0;
+ margin-right: 0;
+ }
}
// Sort indicators
diff --git a/WebContent/VAADIN/themes/runo/runo.scss b/WebContent/VAADIN/themes/runo/runo.scss
index 73566be8c3..d481476d4c 100644
--- a/WebContent/VAADIN/themes/runo/runo.scss
+++ b/WebContent/VAADIN/themes/runo/runo.scss
@@ -3,18 +3,18 @@ $line-height: 18px !default;
// Override Base Grid variables
-$v-grid-border: 1px solid #b6bbbc;
-$v-grid-cell-vertical-border: 1px solid #d4d4d4;
-$v-grid-cell-vertical-border: none;
-$v-grid-cell-horizontal-border: none;
-$v-grid-cell-focused-border: 1px solid #57a7ed;
-$v-grid-row-height: 26px;
-$v-grid-header-row-height: 36px;
+$v-grid-border: 1px solid #b6bbbc !default;
+$v-grid-cell-vertical-border: 1px solid #d4d4d4 !default;
+$v-grid-cell-vertical-border: none !default;
+$v-grid-cell-horizontal-border: none !default;
+$v-grid-cell-focused-border: 1px solid #57a7ed !default;
+$v-grid-row-height: 26px !default;
+$v-grid-header-row-height: 36px !default;
$v-grid-row-background-color: #fff !default;
-$v-grid-row-stripe-background-color:#eff0f1;
-$v-grid-row-selected-background-color: #57a7ed;
-$v-grid-header-font-size: 15px;
-$v-grid-header-background-color: #e7e9ea;
+$v-grid-row-stripe-background-color:#eff0f1 !default;
+$v-grid-row-selected-background-color: #57a7ed !default;
+$v-grid-header-font-size: 15px !default;
+$v-grid-header-background-color: #e7e9ea !default;
@import "../base/base.scss";
diff --git a/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt b/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt
new file mode 100644
index 0000000000..dff31dd51f
--- /dev/null
+++ b/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt
@@ -0,0 +1 @@
+Just ordinary contents here \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/tests-tickets/ordinary.txt b/WebContent/VAADIN/themes/tests-tickets/ordinary.txt
new file mode 100644
index 0000000000..dff31dd51f
--- /dev/null
+++ b/WebContent/VAADIN/themes/tests-tickets/ordinary.txt
@@ -0,0 +1 @@
+Just ordinary contents here \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt b/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt
new file mode 100644
index 0000000000..dff31dd51f
--- /dev/null
+++ b/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt
@@ -0,0 +1 @@
+Just ordinary contents here \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/valo/components/_grid.scss b/WebContent/VAADIN/themes/valo/components/_grid.scss
index 27d421b9f2..e9b4d249c7 100644
--- a/WebContent/VAADIN/themes/valo/components/_grid.scss
+++ b/WebContent/VAADIN/themes/valo/components/_grid.scss
@@ -21,6 +21,11 @@ $v-grid-details-marker-width: first-number($v-grid-border) * 2 !default;
$v-grid-details-marker-color: $v-selection-color !default;
$v-grid-details-border-top: valo-border($color: $v-grid-border-color-source, $strength: 0.3) !default;
$v-grid-details-border-top-stripe: valo-border($color: $v-grid-row-stripe-background-color, $strength: 0.3) !default;
+
+$v-grid-border-size: 1px !default;
+$v-grid-border: $v-grid-border-size solid #ddd !default;
+$v-grid-cell-vertical-border: $v-grid-border !default;
+$v-grid-cell-horizontal-border: $v-grid-cell-vertical-border !default;
$v-grid-details-border-bottom: $v-grid-cell-horizontal-border !default;
$v-grid-details-border-bottom-stripe: $v-grid-cell-horizontal-border !default;
@@ -119,6 +124,10 @@ $v-grid-details-border-bottom-stripe: $v-grid-cell-horizontal-border !default;
vertical-align: middle;
}
+ &.not-editable.#{$primary-stylename}-cell {
+ float: none;
+ }
+
.error::before {
border-top: round($v-unit-size / 4) solid $v-error-indicator-color;
border-right: round($v-unit-size / 4) solid transparent;
@@ -203,9 +212,6 @@ $v-grid-details-border-bottom-stripe: $v-grid-cell-horizontal-border !default;
// Sidebar
.#{$primary-stylename}-sidebar.v-contextmenu {
&.open {
- .#{$primary-stylename}-sidebar-button:after {
- font-size: 20px;
- }
.#{$primary-stylename}-sidebar-content {
margin: 0 0 2px;
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss b/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss
index e97b2fe8d4..c94d48ae14 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss
@@ -1,6 +1,12 @@
+// Bourbon 3.2.4
+// http://bourbon.io
+// Copyright 2011-2015 thoughtbot, inc.
+// MIT License
+
// Settings
@import "settings/prefixer";
@import "settings/px-to-em";
+@import "settings/asset-pipeline";
// Custom Helpers
@import "helpers/gradient-positions-parser";
@@ -11,12 +17,14 @@
@import "helpers/shape-size-stripper";
// Custom Functions
+@import "functions/color-lightness";
@import "functions/flex-grid";
-@import "functions/grid-width";
@import "functions/golden-ratio";
+@import "functions/grid-width";
@import "functions/linear-gradient";
@import "functions/modular-scale";
@import "functions/px-to-em";
+@import "functions/px-to-rem";
@import "functions/radial-gradient";
@import "functions/strip-units";
@import "functions/tint-shade";
@@ -34,8 +42,10 @@
@import "css3/box-sizing";
@import "css3/calc";
@import "css3/columns";
+@import "css3/filter";
@import "css3/flex-box";
@import "css3/font-face";
+@import "css3/font-feature-settings";
@import "css3/hyphens";
@import "css3/hidpi-media-query";
@import "css3/image-rendering";
@@ -56,14 +66,14 @@
@import "addons/ellipsis";
@import "addons/font-family";
@import "addons/hide-text";
-//@import "addons/html5-input-types";
+@import "addons/html5-input-types";
@import "addons/position";
@import "addons/prefixer";
-@import "addons/rem";
@import "addons/retina-image";
@import "addons/size";
@import "addons/timing-functions";
@import "addons/triangle";
+@import "addons/word-wrap";
// Soon to be deprecated Mixins
@import "bourbon-deprecated-upcoming";
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss
index fcc39fdf35..14a89e480c 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss
@@ -1,38 +1,51 @@
-@mixin button ($style: simple, $base-color: #4294f0) {
+@mixin button ($style: simple, $base-color: #4294f0, $text-size: inherit, $padding: 7px 18px) {
- @if type-of($style) == color {
+ @if type-of($style) == string and type-of($base-color) == color {
+ @include buttonstyle($style, $base-color, $text-size, $padding);
+ }
+
+ @if type-of($style) == string and type-of($base-color) == number {
+ $padding: $text-size;
+ $text-size: $base-color;
+ $base-color: #4294f0;
+
+ @if $padding == inherit {
+ $padding: 7px 18px;
+ }
+
+ @include buttonstyle($style, $base-color, $text-size, $padding);
+ }
+
+ @if type-of($style) == color and type-of($base-color) == color {
$base-color: $style;
$style: simple;
+ @include buttonstyle($style, $base-color, $text-size, $padding);
}
- // Grayscale button
- @if $base-color == grayscale($base-color) {
- @if $style == simple {
- @include simple($base-color, $grayscale: true);
- }
+ @if type-of($style) == color and type-of($base-color) == number {
+ $padding: $text-size;
+ $text-size: $base-color;
+ $base-color: $style;
+ $style: simple;
- @else if $style == shiny {
- @include shiny($base-color, $grayscale: true);
+ @if $padding == inherit {
+ $padding: 7px 18px;
}
- @else if $style == pill {
- @include pill($base-color, $grayscale: true);
- }
+ @include buttonstyle($style, $base-color, $text-size, $padding);
}
- // Colored button
- @else {
- @if $style == simple {
- @include simple($base-color);
- }
+ @if type-of($style) == number {
+ $padding: $base-color;
+ $text-size: $style;
+ $base-color: #4294f0;
+ $style: simple;
- @else if $style == shiny {
- @include shiny($base-color);
+ @if $padding == #4294f0 {
+ $padding: 7px 18px;
}
- @else if $style == pill {
- @include pill($base-color);
- }
+ @include buttonstyle($style, $base-color, $text-size, $padding);
}
&:disabled {
@@ -42,16 +55,55 @@
}
+// Selector Style Button
+//************************************************************************//
+@mixin buttonstyle($type, $b-color, $t-size, $pad) {
+ // Grayscale button
+ @if $type == simple and $b-color == grayscale($b-color) {
+ @include simple($b-color, true, $t-size, $pad);
+ }
+
+ @if $type == shiny and $b-color == grayscale($b-color) {
+ @include shiny($b-color, true, $t-size, $pad);
+ }
+
+ @if $type == pill and $b-color == grayscale($b-color) {
+ @include pill($b-color, true, $t-size, $pad);
+ }
+
+ @if $type == flat and $b-color == grayscale($b-color) {
+ @include flat($b-color, true, $t-size, $pad);
+ }
+
+ // Colored button
+ @if $type == simple {
+ @include simple($b-color, false, $t-size, $pad);
+ }
+
+ @else if $type == shiny {
+ @include shiny($b-color, false, $t-size, $pad);
+ }
+
+ @else if $type == pill {
+ @include pill($b-color, false, $t-size, $pad);
+ }
+
+ @else if $type == flat {
+ @include flat($b-color, false, $t-size, $pad);
+ }
+}
+
+
// Simple Button
//************************************************************************//
-@mixin simple($base-color, $grayscale: false) {
+@mixin simple($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%);
$stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%);
$text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%);
- @if lightness($base-color) > 70% {
+ @if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@@ -68,10 +120,10 @@
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
- font-size: inherit;
+ font-size: $textsize;
font-weight: bold;
@include linear-gradient ($base-color, $stop-gradient);
- padding: 7px 18px;
+ padding: $padding;
text-decoration: none;
text-shadow: 0 1px 0 $text-shadow;
background-clip: padding-box;
@@ -92,7 +144,8 @@
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
}
- &:active:not(:disabled) {
+ &:active:not(:disabled),
+ &:focus:not(:disabled) {
$border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%);
@@ -102,14 +155,14 @@
}
border: 1px solid $border-active;
- box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active, 0 1px 1px 0 #eee;
+ box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active;
}
}
// Shiny Button
//************************************************************************//
-@mixin shiny($base-color, $grayscale: false) {
+@mixin shiny($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81);
$border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122);
@@ -119,7 +172,7 @@
$text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114);
$third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48);
- @if lightness($base-color) > 70% {
+ @if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@@ -140,10 +193,10 @@
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
- font-size: inherit;
+ font-size: $textsize;
font-weight: bold;
@include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%);
- padding: 8px 20px;
+ padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
@@ -168,21 +221,22 @@
$fourth-stop-hover 100%);
}
- &:active:not(:disabled) {
+ &:active:not(:disabled),
+ &:focus:not(:disabled) {
$inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122);
@if $grayscale == true {
$inset-shadow-active: grayscale($inset-shadow-active);
}
- box-shadow: inset 0 0 20px 0 $inset-shadow-active, 0 1px 0 #fff;
+ box-shadow: inset 0 0 20px 0 $inset-shadow-active;
}
}
// Pill Button
//************************************************************************//
-@mixin pill($base-color, $grayscale: false) {
+@mixin pill($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%);
@@ -191,7 +245,7 @@
$stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%);
$text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%);
- @if lightness($base-color) > 70% {
+ @if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@@ -208,14 +262,14 @@
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
border-radius: 16px;
- box-shadow: inset 0 1px 0 0 $inset-shadow, 0 1px 2px 0 #b3b3b3;
+ box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
- font-size: inherit;
+ font-size: $textsize;
font-weight: normal;
line-height: 1;
@include linear-gradient ($base-color, $stop-gradient);
- padding: 5px 16px;
+ padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
@@ -249,7 +303,8 @@
background-clip: padding-box;
}
- &:active:not(:disabled) {
+ &:active:not(:disabled),
+ &:focus:not(:disabled) {
$active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%);
$border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%);
$border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%);
@@ -267,7 +322,53 @@
background: $active-color;
border: 1px solid $border-active;
border-bottom: 1px solid $border-bottom-active;
- box-shadow: inset 0 0 6px 3px $inset-shadow-active, 0 1px 0 0 #fff;
+ box-shadow: inset 0 0 6px 3px $inset-shadow-active;
text-shadow: 0 -1px 1px $text-shadow-active;
}
}
+
+
+
+// Flat Button
+//************************************************************************//
+@mixin flat($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
+ $color: hsl(0, 0, 100%);
+
+ @if is-light($base-color) {
+ $color: hsl(0, 0, 20%);
+ }
+
+ background-color: $base-color;
+ border-radius: 3px;
+ border: none;
+ color: $color;
+ display: inline-block;
+ font-size: inherit;
+ font-weight: bold;
+ padding: 7px 18px;
+ text-decoration: none;
+ background-clip: padding-box;
+
+ &:hover:not(:disabled){
+ $base-color-hover: adjust-color($base-color, $saturation: 4%, $lightness: 5%);
+
+ @if $grayscale == true {
+ $base-color-hover: grayscale($base-color-hover);
+ }
+
+ background-color: $base-color-hover;
+ cursor: pointer;
+ }
+
+ &:active:not(:disabled),
+ &:focus:not(:disabled) {
+ $base-color-active: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
+
+ @if $grayscale == true {
+ $base-color-active: grayscale($base-color-active);
+ }
+
+ background-color: $base-color-active;
+ cursor: pointer;
+ }
+}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss
index 4818f62fd8..742f1031a4 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss
@@ -57,9 +57,6 @@
$right: $pre + "-right" + if($suf, "-#{$suf}", "");
$all: $pre + if($suf, "-#{$suf}", "");
- // Get list inside $vals (is there a better way?)
- @each $val in $vals { $vals: $val; }
-
$vals: collapse-directionals($vals);
@if contains-falsy($vals) {
@@ -94,21 +91,21 @@
}
@mixin margin($vals...) {
- @include directional-property(margin, false, $vals);
+ @include directional-property(margin, false, $vals...);
}
@mixin padding($vals...) {
- @include directional-property(padding, false, $vals);
+ @include directional-property(padding, false, $vals...);
}
@mixin border-style($vals...) {
- @include directional-property(border, style, $vals);
+ @include directional-property(border, style, $vals...);
}
@mixin border-color($vals...) {
- @include directional-property(border, color, $vals);
+ @include directional-property(border, color, $vals...);
}
@mixin border-width($vals...) {
- @include directional-property(border, width, $vals);
+ @include directional-property(border, width, $vals...);
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss
index 26fc879021..8428e4e194 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss
@@ -22,7 +22,7 @@ $inputs-list: 'input[type="email"]',
$unquoted-inputs-list: ();
@each $input-type in $inputs-list {
- $unquoted-inputs-list: append($unquoted-inputs-list, unquote($input-type), comma) !global;
+ $unquoted-inputs-list: append($unquoted-inputs-list, unquote($input-type), comma);
}
$all-text-inputs: $unquoted-inputs-list;
@@ -33,7 +33,7 @@ $all-text-inputs: $unquoted-inputs-list;
$all-text-inputs-hover: ();
@each $input-type in $unquoted-inputs-list {
$input-type-hover: $input-type + ":hover";
- $all-text-inputs-hover: append($all-text-inputs-hover, $input-type-hover, comma) !global;
+ $all-text-inputs-hover: append($all-text-inputs-hover, $input-type-hover, comma);
}
// Focus Pseudo-class
@@ -41,7 +41,7 @@ $all-text-inputs-hover: ();
$all-text-inputs-focus: ();
@each $input-type in $unquoted-inputs-list {
$input-type-focus: $input-type + ":focus";
- $all-text-inputs-focus: append($all-text-inputs-focus, $input-type-focus, comma) !global;
+ $all-text-inputs-focus: append($all-text-inputs-focus, $input-type-focus, comma);
}
// You must use interpolation on the variable:
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss
index aba34edcd9..31a0699769 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss
@@ -14,19 +14,19 @@
position: $position;
- @if ($top and $top == auto) or (type-of($top) == number and not unitless($top)) {
+ @if ($top and $top == auto) or (type-of($top) == number and not(unitless($top))) {
top: $top;
}
- @if ($right and $right == auto) or (type-of($right) == number and not unitless($right)) {
+ @if ($right and $right == auto) or (type-of($right) == number and not(unitless($right))) {
right: $right;
}
- @if ($bottom and $bottom == auto) or (type-of($bottom) == number and not unitless($bottom)) {
+ @if ($bottom and $bottom == auto) or (type-of($bottom) == number and not(unitless($bottom))) {
bottom: $bottom;
}
- @if ($left and $left == auto) or (type-of($left) == number and not unitless($left)) {
+ @if ($left and $left == auto) or (type-of($left) == number and not(unitless($left))) {
left: $left;
}
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss
deleted file mode 100644
index ddd7022b44..0000000000
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss
+++ /dev/null
@@ -1,33 +0,0 @@
-@mixin rem($property, $size, $base: $em-base) {
- @if not unitless($base) {
- $base: strip-units($base);
- }
-
- $unitless_values: ();
- @each $num in $size {
- @if not unitless($num) {
- @if unit($num) == "em" {
- $num: $num * $base;
- }
-
- $num: strip-units($num);
- }
-
- $unitless_values: append($unitless_values, $num);
- }
- $size: $unitless_values;
-
- $pixel_values: ();
- $rem_values: ();
- @each $value in $pxval {
- $pixel_value: $value * 1px;
- $pixel_values: append($pixel_values, $pixel_value);
-
- $rem_value: ($value / $base) * 1rem;
- $rem_values: append($rem_values, $rem_value);
- }
-
- #{$property}: $pixel_values;
- #{$property}: $rem_values;
-}
-
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss
index 7931bd1333..3995c1970a 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss
@@ -1,4 +1,4 @@
-@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: false) {
+@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: $asset-pipeline) {
@if $asset-pipeline {
background-image: image-url("#{$filename}.#{$extension}");
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss
index 51b2410914..5ecc6f9dcf 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss
@@ -1,5 +1,5 @@
// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie)
-// Timing functions are the same as demo'ed here: http://jqueryui.com/demos/effect/easing.html
+// Timing functions are the same as demo'ed here: http://jqueryui.com/resources/demos/effect/easing.html
// EASE IN
$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530);
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss
index 0e02aca2ca..3b29e2c3c0 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss
@@ -2,44 +2,85 @@
height: 0;
width: 0;
+ $width: nth($size, 1);
+ $height: nth($size, length($size));
+
+ $foreground-color: nth($color, 1);
+ $background-color: transparent !default;
+ @if (length($color) == 2) {
+ $background-color: nth($color, 2);
+ }
+
@if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) {
- border-color: transparent;
- border-style: solid;
- border-width: $size / 2;
+
+ $width: $width / 2;
+ $height: if(length($size) > 1, $height, $height/2);
@if $direction == up {
- border-bottom-color: $color;
+ border-left: $width solid $background-color;
+ border-right: $width solid $background-color;
+ border-bottom: $height solid $foreground-color;
} @else if $direction == right {
- border-left-color: $color;
+ border-top: $width solid $background-color;
+ border-bottom: $width solid $background-color;
+ border-left: $height solid $foreground-color;
} @else if $direction == down {
- border-top-color: $color;
+ border-left: $width solid $background-color;
+ border-right: $width solid $background-color;
+ border-top: $height solid $foreground-color;
} @else if $direction == left {
- border-right-color: $color;
+ border-top: $width solid $background-color;
+ border-bottom: $width solid $background-color;
+ border-right: $height solid $foreground-color;
}
}
@else if ($direction == up-right) or ($direction == up-left) {
- border-top: $size solid $color;
+ border-top: $height solid $foreground-color;
@if $direction == up-right {
- border-left: $size solid transparent;
+ border-left: $width solid $background-color;
} @else if $direction == up-left {
- border-right: $size solid transparent;
+ border-right: $width solid $background-color;
}
}
@else if ($direction == down-right) or ($direction == down-left) {
- border-bottom: $size solid $color;
+ border-bottom: $height solid $foreground-color;
@if $direction == down-right {
- border-left: $size solid transparent;
+ border-left: $width solid $background-color;
} @else if $direction == down-left {
- border-right: $size solid transparent;
+ border-right: $width solid $background-color;
}
}
+
+ @else if ($direction == inset-up) {
+ border-width: $height $width;
+ border-style: solid;
+ border-color: $background-color $background-color $foreground-color;
+ }
+
+ @else if ($direction == inset-down) {
+ border-width: $height $width;
+ border-style: solid;
+ border-color: $foreground-color $background-color $background-color;
+ }
+
+ @else if ($direction == inset-right) {
+ border-width: $width $height;
+ border-style: solid;
+ border-color: $background-color $background-color $background-color $foreground-color;
+ }
+
+ @else if ($direction == inset-left) {
+ border-width: $width $height;
+ border-style: solid;
+ border-color: $background-color $foreground-color $background-color $background-color;
+ }
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss
new file mode 100644
index 0000000000..9734a597cd
--- /dev/null
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss
@@ -0,0 +1,8 @@
+@mixin word-wrap($wrap: break-word) {
+ word-wrap: $wrap;
+
+ @if $wrap == break-word {
+ overflow-wrap: break-word;
+ word-break: break-all;
+ }
+}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss
index 42274a4eeb..96f601c1a8 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss
@@ -15,7 +15,7 @@
@mixin column-fill($arg: auto) {
// auto || length
- @include prefixer(columns-fill, $arg, webkit moz spec);
+ @include prefixer(column-fill, $arg, webkit moz spec);
}
@mixin column-rule($arg) {
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss
new file mode 100644
index 0000000000..8560d77676
--- /dev/null
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss
@@ -0,0 +1,5 @@
+@mixin filter($function: none) {
+ // <filter-function> [<filter-function]* | none
+ @include prefixer(filter, $function, webkit spec);
+}
+
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_flex-box.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_flex-box.scss
index b48476e870..34a3a0522b 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_flex-box.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_flex-box.scss
@@ -78,7 +78,7 @@
display: flex;
}
- @elseif $value == "inline-flex" {
+ @else if $value == "inline-flex" {
display: -webkit-inline-box;
display: -moz-inline-box;
display: inline-box;
@@ -124,16 +124,16 @@
$value-2009: horizontal;
}
- @elseif $value == "row-reverse" {
+ @else if $value == "row-reverse" {
$value-2009: horizontal;
$direction: reverse;
}
- @elseif $value == column {
+ @else if $value == column {
$value-2009: vertical;
}
- @elseif $value == "column-reverse" {
+ @else if $value == "column-reverse" {
$value-2009: vertical;
$direction: reverse;
}
@@ -162,11 +162,11 @@
$alt-value: single;
}
- @elseif $value == wrap {
+ @else if $value == wrap {
$alt-value: multiple;
}
- @elseif $value == "wrap-reverse" {
+ @else if $value == "wrap-reverse" {
$alt-value: multiple;
}
@@ -224,15 +224,15 @@
$alt-value: start;
}
- @elseif $value == "flex-end" {
+ @else if $value == "flex-end" {
$alt-value: end;
}
- @elseif $value == "space-between" {
+ @else if $value == "space-between" {
$alt-value: justify;
}
- @elseif $value == "space-around" {
+ @else if $value == "space-around" {
$alt-value: center;
}
@@ -257,7 +257,7 @@
$alt-value: start;
}
- @elseif $value == "flex-end" {
+ @else if $value == "flex-end" {
$alt-value: end;
}
@@ -280,7 +280,7 @@
$value-2011: start;
}
- @elseif $value == "flex-end" {
+ @else if $value == "flex-end" {
$value-2011: end;
}
@@ -300,15 +300,15 @@
$value-2011: start;
}
- @elseif $value == "flex-end" {
+ @else if $value == "flex-end" {
$value-2011: end;
}
- @elseif $value == "space-between" {
+ @else if $value == "space-between" {
$value-2011: justify;
}
- @elseif $value == "space-around" {
+ @else if $value == "space-around" {
$value-2011: distribute;
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-face.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-face.scss
index 029ee8fe88..fbf483fde9 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-face.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-face.scss
@@ -1,6 +1,6 @@
// Order of the includes matters, and it is: normal, bold, italic, bold+italic.
-@mixin font-face($font-family, $file-path, $weight: normal, $style: normal, $asset-pipeline: false ) {
+@mixin font-face($font-family, $file-path, $weight: normal, $style: normal, $asset-pipeline: $asset-pipeline) {
@font-face {
font-family: $font-family;
font-weight: $weight;
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-feature-settings.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-feature-settings.scss
new file mode 100644
index 0000000000..8a9f536775
--- /dev/null
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-feature-settings.scss
@@ -0,0 +1,10 @@
+// Font feature settings mixin and property default.
+// Examples: @include font-feature-settings("liga");
+// @include font-feature-settings("lnum" false);
+// @include font-feature-settings("pnum" 1, "kern" 0);
+// @include font-feature-settings("ss01", "ss02");
+
+@mixin font-feature-settings($settings...) {
+ @if length($settings) == 0 { $settings: none; }
+ @include prefixer(font-feature-settings, $settings, webkit moz ms spec);
+} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_image-rendering.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_image-rendering.scss
index d4bac3ce0d..03432c637d 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_image-rendering.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_image-rendering.scss
@@ -1,6 +1,7 @@
@mixin image-rendering ($mode:auto) {
@if ($mode == crisp-edges) {
+ -ms-interpolation-mode: nearest-neighbor; // IE8+
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_keyframes.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_keyframes.scss
index a9af53da4f..cc12be79bd 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_keyframes.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_keyframes.scss
@@ -20,19 +20,16 @@
@content;
}
}
- @if $original-prefix-for-spec {
- @include disable-prefix-for-all();
- $prefix-for-spec: true;
- // Chrome supports the standard keyframes syntax, but not the standard transform syntax
- $prefix-for-webkit: true;
- @keyframes #{$name} {
- @content;
- }
- }
$prefix-for-webkit: $original-prefix-for-webkit;
$prefix-for-mozilla: $original-prefix-for-mozilla;
$prefix-for-microsoft: $original-prefix-for-microsoft;
$prefix-for-opera: $original-prefix-for-opera;
$prefix-for-spec: $original-prefix-for-spec;
+
+ @if $original-prefix-for-spec {
+ @keyframes #{$name} {
+ @content;
+ }
+ }
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_placeholder.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_placeholder.scss
index 22fd92b4f2..5682fd097a 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_placeholder.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_placeholder.scss
@@ -1,29 +1,8 @@
-$placeholders: '-webkit-input-placeholder',
- '-moz-placeholder',
- '-ms-input-placeholder';
-
@mixin placeholder {
+ $placeholders: ":-webkit-input" ":-moz" "-moz" "-ms-input";
@each $placeholder in $placeholders {
- @if $placeholder == "-webkit-input-placeholder" {
- &::#{$placeholder} {
- @content;
- }
- }
- @else if $placeholder == "-moz-placeholder" {
- // FF 18-
- &:#{$placeholder} {
- @content;
- }
-
- // FF 19+
- &::#{$placeholder} {
- @content;
- }
- }
- @else {
- &:#{$placeholder} {
- @content;
- }
+ &:#{$placeholder}-placeholder {
+ @content;
}
}
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_transition.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_transition.scss
index fe18933fef..5ad4c0aed2 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_transition.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_transition.scss
@@ -4,13 +4,56 @@
// @include transition-property (transform, opacity);
@mixin transition ($properties...) {
- @if length($properties) >= 1 {
- @include prefixer(transition, $properties, webkit moz spec);
+ // Fix for vendor-prefix transform property
+ $needs-prefixes: false;
+ $webkit: ();
+ $moz: ();
+ $spec: ();
+
+ // Create lists for vendor-prefixed transform
+ @each $list in $properties {
+ @if nth($list, 1) == "transform" {
+ $needs-prefixes: true;
+ $list1: -webkit-transform;
+ $list2: -moz-transform;
+ $list3: ();
+
+ @each $var in $list {
+ $list3: join($list3, $var);
+
+ @if $var != "transform" {
+ $list1: join($list1, $var);
+ $list2: join($list2, $var);
+ }
+ }
+
+ $webkit: append($webkit, $list1);
+ $moz: append($moz, $list2);
+ $spec: append($spec, $list3);
+ }
+
+ // Create lists for non-prefixed transition properties
+ @else {
+ $webkit: append($webkit, $list, comma);
+ $moz: append($moz, $list, comma);
+ $spec: append($spec, $list, comma);
+ }
}
+ @if $needs-prefixes {
+ -webkit-transition: $webkit;
+ -moz-transition: $moz;
+ transition: $spec;
+ }
@else {
- $properties: all 0.15s ease-out 0s;
- @include prefixer(transition, $properties, webkit moz spec);
+ @if length($properties) >= 1 {
+ @include prefixer(transition, $properties, webkit moz spec);
+ }
+
+ @else {
+ $properties: all 0.15s ease-out 0s;
+ @include prefixer(transition, $properties, webkit moz spec);
+ }
}
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss
new file mode 100644
index 0000000000..8c6df4e256
--- /dev/null
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss
@@ -0,0 +1,13 @@
+// Programatically determines whether a color is light or dark
+// Returns a boolean
+// More details here http://robots.thoughtbot.com/closer-look-color-lightness
+
+@function is-light($hex-color) {
+ $-local-red: red(rgba($hex-color, 1.0));
+ $-local-green: green(rgba($hex-color, 1.0));
+ $-local-blue: blue(rgba($hex-color, 1.0));
+
+ $-local-lightness: ($-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722) / 255;
+
+ @return $-local-lightness > .6;
+}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss
index 0a7185916c..afc59eb954 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss
@@ -1,4 +1,4 @@
-// Scaling Varaibles
+// Scaling Variables
$golden: 1.618;
$minor-second: 1.067;
$major-second: 1.125;
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss
new file mode 100644
index 0000000000..96b244e4cb
--- /dev/null
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss
@@ -0,0 +1,15 @@
+// Convert pixels to rems
+// eg. for a relational value of 12px write rem(12)
+// Assumes $em-base is the font-size of <html>
+
+@function rem($pxval) {
+ @if not unitless($pxval) {
+ $pxval: strip-units($pxval);
+ }
+
+ $base: $em-base;
+ @if not unitless($base) {
+ $base: strip-units($base);
+ }
+ @return ($pxval / $base) * 1rem;
+}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss
index 6ceae72102..49e621d63d 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss
@@ -2,21 +2,21 @@
// Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background
//************************************************************************//
@function transition-property-names($props, $vendor: false) {
- $new-props: ();
-
- @each $prop in $props {
- $new-props: append($new-props, transition-property-name($prop, $vendor), comma);
- }
+ $new-props: ();
+
+ @each $prop in $props {
+ $new-props: append($new-props, transition-property-name($prop, $vendor), comma);
+ }
- @return $new-props;
+ @return $new-props;
}
@function transition-property-name($prop, $vendor: false) {
- // put other properties that need to be prefixed here aswell
- @if $vendor and $prop == transform {
- @return unquote('-' + $vendor + '-' + $prop);
- }
- @else {
- @return $prop;
- }
+ // put other properties that need to be prefixed here aswell
+ @if $vendor and $prop == transform {
+ @return unquote('-' + $vendor + '-' + $prop);
+ }
+ @else {
+ @return $prop;
+ }
} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss b/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss
index 5765676838..c145110a17 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss
@@ -16,11 +16,11 @@
}
@if $vendor {
- $vendor-gradients: -#{$vendor}-#{$gradient-type}-gradient(#{$pre-spec} $gradients);
+ $vendor-gradients: "-#{$vendor}-#{$gradient-type}-gradient(#{$pre-spec} #{$gradients})";
}
@else if $vendor == false {
$vendor-gradients: "#{$gradient-type}-gradient(#{$spec} #{$gradients})";
- $vendor-gradients: unquote($vendor-gradients);
}
+ $vendor-gradients: unquote($vendor-gradients);
@return $vendor-gradients;
}
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss
new file mode 100644
index 0000000000..d481a6afb1
--- /dev/null
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss
@@ -0,0 +1 @@
+$asset-pipeline: false !default;
diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss
index c29a961919..ecab49fb54 100644
--- a/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss
+++ b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss
@@ -1,6 +1,6 @@
// Variable settings for /addons/prefixer.scss
-$prefix-for-webkit: true;
-$prefix-for-mozilla: true;
-$prefix-for-microsoft: true;
-$prefix-for-opera: true;
-$prefix-for-spec: true; // required for keyframe mixin
+$prefix-for-webkit: true !default;
+$prefix-for-mozilla: true !default;
+$prefix-for-microsoft: true !default;
+$prefix-for-opera: true !default;
+$prefix-for-spec: true !default; // required for keyframe mixin
diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml
index c097fcf1b7..1879175109 100644
--- a/WebContent/WEB-INF/web.xml
+++ b/WebContent/WEB-INF/web.xml
@@ -128,6 +128,16 @@
<async-supported>true</async-supported>
</servlet>
+ <servlet>
+ <servlet-name>VaadinApplicationRunnerWithPushTimeout</servlet-name>
+ <servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class>
+ <init-param>
+ <param-name>pushLongPollingSuspendTimeout</param-name>
+ <param-value>10000</param-value>
+ </init-param>
+ <async-supported>true</async-supported>
+ </servlet>
+
<!-- For testing GAE - the deployment script changes this to use GAEVaadinServlet -->
<servlet>
<servlet-name>IntegrationTest</servlet-name>
@@ -173,6 +183,11 @@
</servlet-mapping>
<servlet-mapping>
+ <servlet-name>VaadinApplicationRunnerWithPushTimeout</servlet-name>
+ <url-pattern>/run-push-timeout/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
<servlet-name>VaadinApplicationRunnerWithJSR356</servlet-name>
<url-pattern>/run-jsr356/*</url-pattern>
</servlet-mapping>
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index b7cdba7887..e9b4a24ce1 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -109,11 +109,18 @@
<h3 id="incompatible">Incompatible or Behavior-altering Changes in @version-minor@</h3>
<ul>
+ <li>Window close shortcuts have been changed, and ESCAPE is no longer a hard-coded default, but rather a soft one,
+ and can be removed. If the <pre>close-shortcut</pre> attribute of the <pre>v-window</pre> element is present,
+ it must list all close shortcuts, including ESCAPE, separated by whitespace. Existing, unchanged code should
+ behave as before. See ticket <a href="https://dev.vaadin.com/ticket/17383">#17383</a> for more information
+ on the reasoning behind the change.</li>
<li>The push path has been changed from /PUSH/ to /PUSH to be compatible with JSR 356.</li>
<li>Widgetset files and other pre-compressed resources are sent as gzip to compatible browsers.
This may interfere with custom response compression solutions that do not respect the Content-Encoding response header.</li>
<li>Unused methods related to the "out of sync" message have been removed from SystemMessages class.</li>
<li>All notifications use the WAI-ARIA alert role to be compatible with Jaws</li>
+ <li>Grid SelectionModels are now Extensions. This update removes all selection related variables and API from
+ GridConnector, GridState, GridServerRpc and GridClientRpc</li>
</ul>
<h3 id="knownissues">Known Issues and Limitations</h3>
<ul>
diff --git a/build/ide.xml b/build/ide.xml
index 4bd839365f..d468473392 100755
--- a/build/ide.xml
+++ b/build/ide.xml
@@ -181,7 +181,7 @@
<property name="js.output.dir" location="WebContent" />
<property name="push.js.dir" location="${basedir}/push/result/js" />
<copy todir="${js.output.dir}">
- <fileset dir="${push.js.dir}" includes="VAADIN/vaadinPush*">
+ <fileset dir="${push.js.dir}" includes="VAADIN/vaadinPush*" excludes="**/*.gz">
</fileset>
</copy>
</target>
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java b/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java
index b7850e6370..2d08329e9a 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java
@@ -16,6 +16,7 @@
package com.vaadin.server.widgetsetutils;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Date;
import com.google.gwt.core.ext.Generator;
@@ -29,6 +30,7 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.client.ui.dd.VAcceptCriterion;
import com.vaadin.client.ui.dd.VAcceptCriterionFactory;
+import com.vaadin.server.widgetsetutils.metadata.ConnectorBundle;
import com.vaadin.shared.ui.dd.AcceptCriterion;
/**
@@ -114,7 +116,9 @@ public class AcceptCriteriaFactoryGenerator extends Generator {
JClassType criteriaType = context.getTypeOracle().findType(
VAcceptCriterion.class.getName());
- for (JClassType clientClass : criteriaType.getSubtypes()) {
+ JClassType[] subtypes = criteriaType.getSubtypes();
+ Arrays.sort(subtypes, ConnectorBundle.jClassComparator);
+ for (JClassType clientClass : subtypes) {
AcceptCriterion annotation = clientClass
.getAnnotation(AcceptCriterion.class);
if (annotation != null) {
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
index 884852f7c8..2b8ccc87d0 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.TreeMap;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
@@ -1185,10 +1186,11 @@ public class ConnectorBundleLoaderFactory extends Generator {
JClassType[] types = serverConnectorType.getSubtypes();
- Map<String, JClassType> mappings = new HashMap<String, JClassType>();
+ Map<String, JClassType> mappings = new TreeMap<String, JClassType>();
// Keep track of what has happened to avoid logging intermediate state
- Map<JClassType, List<JClassType>> replaced = new HashMap<JClassType, List<JClassType>>();
+ Map<JClassType, List<JClassType>> replaced = new TreeMap<JClassType, List<JClassType>>(
+ ConnectorBundle.jClassComparator);
for (JClassType type : types) {
Connect connectAnnotation = type.getAnnotation(Connect.class);
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
index fedc86fbf6..b4531eb08e 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
@@ -19,12 +19,16 @@ import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
@@ -37,7 +41,6 @@ import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ServerConnector;
@@ -54,6 +57,22 @@ import elemental.json.JsonValue;
public class ConnectorBundle {
private static final String FAIL_IF_NOT_SERIALIZABLE = "vFailIfNotSerializable";
+ public static final Comparator<JClassType> jClassComparator = new Comparator<JClassType>() {
+ @Override
+ public int compare(JClassType o1, JClassType o2) {
+ return o1.getQualifiedSourceName().compareTo(
+ o2.getQualifiedSourceName());
+ }
+ };
+
+ public static final Comparator<JMethod> jMethodComparator = new Comparator<JMethod>() {
+ @Override
+ public int compare(JMethod o1, JMethod o2) {
+ return o1.getReadableDeclaration().compareTo(
+ o2.getReadableDeclaration());
+ }
+ };
+
private final String name;
private final ConnectorBundle previousBundle;
private final Collection<TypeVisitor> visitors;
@@ -61,24 +80,42 @@ public class ConnectorBundle {
private final Set<JType> hasSerializeSupport = new HashSet<JType>();
private final Set<JType> needsSerializeSupport = new HashSet<JType>();
- private final Map<JType, GeneratedSerializer> serializers = new HashMap<JType, GeneratedSerializer>();
- private final Map<JClassType, JType> presentationTypes = new HashMap<JClassType, JType>();
- private final Set<JClassType> needsSuperClass = new HashSet<JClassType>();
- private final Set<JClassType> needsGwtConstructor = new HashSet<JClassType>();
+ private final Map<JType, GeneratedSerializer> serializers = new TreeMap<JType, GeneratedSerializer>(
+ new Comparator<JType>() {
+ @Override
+ public int compare(JType o1, JType o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ });
+
+ private final Map<JClassType, Map<JMethod, Set<MethodAttribute>>> methodAttributes = new TreeMap<JClassType, Map<JMethod, Set<MethodAttribute>>>(
+ jClassComparator);
+ private final Set<JClassType> needsSuperClass = new TreeSet<JClassType>(
+ jClassComparator);
+ private final Set<JClassType> needsGwtConstructor = new TreeSet<JClassType>(
+ jClassComparator);
private final Set<JClassType> visitedTypes = new HashSet<JClassType>();
- private final Set<JClassType> needsProxySupport = new HashSet<JClassType>();
- private final Map<JClassType, Set<String>> identifiers = new HashMap<JClassType, Set<String>>();
- private final Map<JClassType, Set<JMethod>> needsReturnType = new HashMap<JClassType, Set<JMethod>>();
- private final Map<JClassType, Set<JMethod>> needsInvoker = new HashMap<JClassType, Set<JMethod>>();
- private final Map<JClassType, Set<JMethod>> needsParamTypes = new HashMap<JClassType, Set<JMethod>>();
- private final Map<JClassType, Set<JMethod>> needsOnStateChange = new HashMap<JClassType, Set<JMethod>>();
-
- private final Map<JClassType, Map<JMethod, Set<MethodAttribute>>> methodAttributes = new HashMap<JClassType, Map<JMethod, Set<MethodAttribute>>>();
-
- private final Set<Property> needsProperty = new HashSet<Property>();
- private final Map<JClassType, Set<Property>> needsDelegateToWidget = new HashMap<JClassType, Set<Property>>();
+ private final Set<JClassType> needsProxySupport = new TreeSet<JClassType>(
+ jClassComparator);
+
+ private final Map<JClassType, JType> presentationTypes = new TreeMap<JClassType, JType>(
+ jClassComparator);
+ private final Map<JClassType, Set<String>> identifiers = new TreeMap<JClassType, Set<String>>(
+ jClassComparator);
+ private final Map<JClassType, Set<JMethod>> needsReturnType = new TreeMap<JClassType, Set<JMethod>>(
+ jClassComparator);
+ private final Map<JClassType, Set<JMethod>> needsInvoker = new TreeMap<JClassType, Set<JMethod>>(
+ jClassComparator);
+ private final Map<JClassType, Set<JMethod>> needsParamTypes = new TreeMap<JClassType, Set<JMethod>>(
+ jClassComparator);
+ private final Map<JClassType, Set<JMethod>> needsOnStateChange = new TreeMap<JClassType, Set<JMethod>>(
+ jClassComparator);
+
+ private final Set<Property> needsProperty = new TreeSet<Property>();
+ private final Map<JClassType, Set<Property>> needsDelegateToWidget = new TreeMap<JClassType, Set<Property>>(
+ jClassComparator);
private ConnectorBundle(String name, ConnectorBundle previousBundle,
Collection<TypeVisitor> visitors,
@@ -369,7 +406,7 @@ public class ConnectorBundle {
}
public Collection<Property> getProperties(JClassType type) {
- HashSet<Property> properties = new HashSet<Property>();
+ Set<Property> properties = new TreeSet<Property>();
properties.addAll(MethodProperty.findProperties(type));
properties.addAll(FieldProperty.findProperties(type));
@@ -463,10 +500,19 @@ public class ConnectorBundle {
}
}
- private <K, V> void addMapping(Map<K, Set<V>> map, K key, V value) {
- Set<V> set = map.get(key);
+ private <K> void addMapping(Map<K, Set<String>> map, K key, String value) {
+ Set<String> set = map.get(key);
+ if (set == null) {
+ set = new TreeSet<String>();
+ map.put(key, set);
+ }
+ set.add(value);
+ }
+
+ private <K> void addMapping(Map<K, Set<JMethod>> map, K key, JMethod value) {
+ Set<JMethod> set = map.get(key);
if (set == null) {
- set = new HashSet<V>();
+ set = new TreeSet<JMethod>(jMethodComparator);
map.put(key, set);
}
set.add(value);
@@ -533,11 +579,26 @@ public class ConnectorBundle {
Map<JMethod, Set<MethodAttribute>> typeData = methodAttributes
.get(type);
if (typeData == null) {
- typeData = new HashMap<JMethod, Set<MethodAttribute>>();
+ typeData = new TreeMap<JMethod, Set<MethodAttribute>>(
+ jMethodComparator);
methodAttributes.put(type, typeData);
}
- addMapping(typeData, method, methodAttribute);
+ Map<JMethod, Set<MethodAttribute>> methods = methodAttributes
+ .get(type);
+ if (methods == null) {
+ methods = new TreeMap<JMethod, Set<MethodAttribute>>(
+ jMethodComparator);
+ methodAttributes.put(type, methods);
+ }
+
+ Set<MethodAttribute> attributes = methods.get(method);
+ if (attributes == null) {
+ attributes = new TreeSet<MethodAttribute>();
+ methods.put(method, attributes);
+ }
+
+ attributes.add(methodAttribute);
}
}
@@ -564,7 +625,7 @@ public class ConnectorBundle {
}
}
- private static Set<Class<?>> frameworkHandledTypes = new HashSet<Class<?>>();
+ private static Set<Class<?>> frameworkHandledTypes = new LinkedHashSet<Class<?>>();
{
frameworkHandledTypes.add(String.class);
frameworkHandledTypes.add(Boolean.class);
@@ -611,7 +672,9 @@ public class ConnectorBundle {
public void setNeedsDelegateToWidget(Property property, JClassType type) {
if (!isNeedsDelegateToWidget(type)) {
- needsDelegateToWidget.put(type, Sets.newHashSet(property));
+ TreeSet<Property> set = new TreeSet<Property>();
+ set.add(property);
+ needsDelegateToWidget.put(type, set);
} else if (!needsDelegateToWidget.get(type).contains(property)) {
needsDelegateToWidget.get(type).add(property);
}
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java
index f07b1c29fd..0c849bead5 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java
@@ -24,7 +24,7 @@ import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.user.rebind.SourceWriter;
-public abstract class Property {
+public abstract class Property implements Comparable<Property> {
private final String name;
private final JClassType beanType;
private final JType propertyType;
@@ -107,6 +107,20 @@ public abstract class Property {
+ getName().hashCode();
}
+ @Override
+ public int compareTo(Property o) {
+ int comp = getName().compareTo(o.getName());
+ if (comp == 0) {
+ comp = getBeanType().getQualifiedSourceName().compareTo(
+ o.getBeanType().getQualifiedSourceName());
+ }
+ if (comp == 0) {
+ comp = getClass().getCanonicalName().compareTo(
+ o.getClass().getCanonicalName());
+ }
+ return comp;
+ }
+
public abstract <T extends Annotation> T getAnnotation(
Class<T> annotationClass);
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 70275218cf..6e20908274 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -62,7 +62,6 @@ import com.vaadin.client.ui.VContextMenu;
import com.vaadin.client.ui.VNotification;
import com.vaadin.client.ui.VOverlay;
import com.vaadin.client.ui.ui.UIConnector;
-import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.VaadinUriResolver;
import com.vaadin.shared.Version;
import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
@@ -1318,20 +1317,19 @@ public class ApplicationConnection implements HasHandlers {
* before the component is updated so the value is correct if called from
* updatedFromUIDL.
*
- * @param paintable
+ * @param connector
* The connector to register event listeners for
* @param eventIdentifier
* The identifier for the event
* @return true if at least one listener has been registered on server side
* for the event identified by eventIdentifier.
* @deprecated As of 7.0. Use
- * {@link AbstractComponentState#hasEventListener(String)}
- * instead
+ * {@link AbstractConnector#hasEventListener(String)} instead
*/
@Deprecated
- public boolean hasEventListeners(ComponentConnector paintable,
+ public boolean hasEventListeners(ComponentConnector connector,
String eventIdentifier) {
- return paintable.hasEventListener(eventIdentifier);
+ return connector.hasEventListener(eventIdentifier);
}
/**
diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java
index 8b274623c1..8dcefddcf5 100644
--- a/client/src/com/vaadin/client/BrowserInfo.java
+++ b/client/src/com/vaadin/client/BrowserInfo.java
@@ -30,6 +30,7 @@ public class BrowserInfo {
private static final String BROWSER_OPERA = "op";
private static final String BROWSER_IE = "ie";
+ private static final String BROWSER_EDGE = "edge";
private static final String BROWSER_FIREFOX = "ff";
private static final String BROWSER_SAFARI = "sa";
@@ -171,6 +172,13 @@ public class BrowserInfo {
minorVersionClass = majorVersionClass
+ browserDetails.getBrowserMinorVersion();
browserEngineClass = ENGINE_TRIDENT;
+ } else if (browserDetails.isEdge()) {
+ browserIdentifier = BROWSER_EDGE;
+ majorVersionClass = browserIdentifier
+ + getBrowserMajorVersion();
+ minorVersionClass = majorVersionClass
+ + browserDetails.getBrowserMinorVersion();
+ browserEngineClass = "";
} else if (browserDetails.isOpera()) {
browserIdentifier = BROWSER_OPERA;
majorVersionClass = browserIdentifier
@@ -225,6 +233,10 @@ public class BrowserInfo {
return browserDetails.isIE();
}
+ public boolean isEdge() {
+ return browserDetails.isEdge();
+ }
+
public boolean isFirefox() {
return browserDetails.isFirefox();
}
@@ -245,6 +257,10 @@ public class BrowserInfo {
return isIE() && getBrowserMajorVersion() == 10;
}
+ public boolean isIE11() {
+ return isIE() && getBrowserMajorVersion() == 11;
+ }
+
public boolean isChrome() {
return browserDetails.isChrome();
}
diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java
index 61cb3c2eb6..66404eeeed 100644
--- a/client/src/com/vaadin/client/ComputedStyle.java
+++ b/client/src/com/vaadin/client/ComputedStyle.java
@@ -155,10 +155,10 @@ public class ComputedStyle {
* the property to retrieve
* @return the double value of the property
*/
- public final int getDoubleProperty(String name) {
+ public final double getDoubleProperty(String name) {
Profiler.enter("ComputedStyle.getDoubleProperty");
String value = getProperty(name);
- int result = parseDoubleNative(value);
+ double result = parseDoubleNative(value);
Profiler.leave("ComputedStyle.getDoubleProperty");
return result;
}
@@ -275,9 +275,87 @@ public class ComputedStyle {
* @return the value from the string before any non-numeric characters or
* NaN if the value cannot be parsed as a number
*/
- private static native int parseDoubleNative(final String value)
+ private static native double parseDoubleNative(final String value)
/*-{
return parseFloat(value);
}-*/;
+ /**
+ * Returns the sum of the top and bottom border width
+ *
+ * @since 7.5.3
+ * @return the sum of the top and bottom border
+ */
+ public double getBorderHeight() {
+ double borderHeight = getDoubleProperty("borderTopWidth");
+ borderHeight += getDoubleProperty("borderBottomWidth");
+
+ return borderHeight;
+ }
+
+ /**
+ * Returns the sum of the left and right border width
+ *
+ * @since 7.5.3
+ * @return the sum of the left and right border
+ */
+ public double getBorderWidth() {
+ double borderWidth = getDoubleProperty("borderLeftWidth");
+ borderWidth += getDoubleProperty("borderRightWidth");
+
+ return borderWidth;
+ }
+
+ /**
+ * Returns the sum of the top and bottom padding
+ *
+ * @since 7.5.3
+ * @return the sum of the top and bottom padding
+ */
+ public double getPaddingHeight() {
+ double paddingHeight = getDoubleProperty("paddingTop");
+ paddingHeight += getDoubleProperty("paddingBottom");
+
+ return paddingHeight;
+ }
+
+ /**
+ * Returns the sum of the top and bottom padding
+ *
+ * @since 7.5.3
+ * @return the sum of the left and right padding
+ */
+ public double getPaddingWidth() {
+ double paddingWidth = getDoubleProperty("paddingLeft");
+ paddingWidth += getDoubleProperty("paddingRight");
+
+ return paddingWidth;
+ }
+
+ /**
+ * Returns the sum of the top and bottom margin
+ *
+ * @since 7.6
+ * @return the sum of the top and bottom margin
+ */
+ public double getMarginHeight() {
+ double marginHeight = getDoubleProperty("marginTop");
+ marginHeight += getDoubleProperty("marginBottom");
+
+ return marginHeight;
+ }
+
+ /**
+ * Returns the sum of the top and bottom margin
+ *
+ * @since 7.6
+ * @return the sum of the left and right margin
+ */
+ public double getMarginWidth() {
+ double marginWidth = getDoubleProperty("marginLeft");
+ marginWidth += getDoubleProperty("marginRight");
+
+ return marginWidth;
+ }
+
}
diff --git a/client/src/com/vaadin/client/EventHelper.java b/client/src/com/vaadin/client/EventHelper.java
index f251215d41..1ee252af0f 100644
--- a/client/src/com/vaadin/client/EventHelper.java
+++ b/client/src/com/vaadin/client/EventHelper.java
@@ -51,7 +51,6 @@ import com.google.gwt.user.client.ui.Widget;
*
*
* </pre>
- *
*/
public class EventHelper {
@@ -69,7 +68,7 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & FocusHandler> HandlerRegistration updateFocusHandler(
T connector, HandlerRegistration handlerRegistration) {
- return updateHandler(connector, FOCUS, handlerRegistration,
+ return updateHandler(connector, connector, FOCUS, handlerRegistration,
FocusEvent.getType(), connector.getWidget());
}
@@ -89,7 +88,7 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & FocusHandler> HandlerRegistration updateFocusHandler(
T connector, HandlerRegistration handlerRegistration, Widget widget) {
- return updateHandler(connector, FOCUS, handlerRegistration,
+ return updateHandler(connector, connector, FOCUS, handlerRegistration,
FocusEvent.getType(), widget);
}
@@ -107,7 +106,7 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & BlurHandler> HandlerRegistration updateBlurHandler(
T connector, HandlerRegistration handlerRegistration) {
- return updateHandler(connector, BLUR, handlerRegistration,
+ return updateHandler(connector, connector, BLUR, handlerRegistration,
BlurEvent.getType(), connector.getWidget());
}
@@ -128,23 +127,21 @@ public class EventHelper {
*/
public static <T extends ComponentConnector & BlurHandler> HandlerRegistration updateBlurHandler(
T connector, HandlerRegistration handlerRegistration, Widget widget) {
- return updateHandler(connector, BLUR, handlerRegistration,
+ return updateHandler(connector, connector, BLUR, handlerRegistration,
BlurEvent.getType(), widget);
}
- private static <H extends EventHandler> HandlerRegistration updateHandler(
- ComponentConnector connector, String eventIdentifier,
+ public static <H extends EventHandler> HandlerRegistration updateHandler(
+ ComponentConnector connector, H handler, String eventIdentifier,
HandlerRegistration handlerRegistration, Type<H> type, Widget widget) {
if (connector.hasEventListener(eventIdentifier)) {
if (handlerRegistration == null) {
- handlerRegistration = widget.addDomHandler((H) connector, type);
+ handlerRegistration = widget.addDomHandler(handler, type);
}
} else if (handlerRegistration != null) {
handlerRegistration.removeHandler();
handlerRegistration = null;
}
return handlerRegistration;
-
}
-
}
diff --git a/client/src/com/vaadin/client/ResourceLoader.java b/client/src/com/vaadin/client/ResourceLoader.java
index 9e9ce5ac49..559768d09c 100644
--- a/client/src/com/vaadin/client/ResourceLoader.java
+++ b/client/src/com/vaadin/client/ResourceLoader.java
@@ -283,8 +283,7 @@ public class ResourceLoader {
* @since 7.2.4
*/
public static boolean supportsInOrderScriptExecution() {
- return BrowserInfo.get().isIE()
- && BrowserInfo.get().getBrowserMajorVersion() >= 11;
+ return BrowserInfo.get().isIE11() || BrowserInfo.get().isEdge();
}
/**
@@ -486,10 +485,11 @@ public class ResourceLoader {
addOnloadHandler(linkElement, new ResourceLoadListener() {
@Override
public void onLoad(ResourceLoadEvent event) {
- // Chrome && IE fires load for errors, must check
+ // Chrome, IE, Edge all fire load for errors, must check
// stylesheet data
if (BrowserInfo.get().isChrome()
- || BrowserInfo.get().isIE()) {
+ || BrowserInfo.get().isIE()
+ || BrowserInfo.get().isEdge()) {
int styleSheetLength = getStyleSheetLength(url);
// Error if there's an empty stylesheet
if (styleSheetLength == 0) {
diff --git a/client/src/com/vaadin/client/SuperDevMode.java b/client/src/com/vaadin/client/SuperDevMode.java
index c72cd73939..f664244715 100644
--- a/client/src/com/vaadin/client/SuperDevMode.java
+++ b/client/src/com/vaadin/client/SuperDevMode.java
@@ -189,7 +189,11 @@ public class SuperDevMode {
if (serverUrl == null || "".equals(serverUrl)) {
serverUrl = "http://localhost:9876/";
} else {
- serverUrl = "http://" + serverUrl + "/";
+ if (serverUrl.contains(":")) {
+ serverUrl = "http://" + serverUrl + "/";
+ } else {
+ serverUrl = "http://" + serverUrl + ":9876/";
+ }
}
if (hasSession(SKIP_RECOMPILE)) {
diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java
index 4e59040298..f3d65cd20a 100644
--- a/client/src/com/vaadin/client/VTooltip.java
+++ b/client/src/com/vaadin/client/VTooltip.java
@@ -89,6 +89,9 @@ public class VTooltip extends VOverlay {
LiveValue.ASSERTIVE);
Roles.getTooltipRole().setAriaRelevantProperty(getElement(),
RelevantValue.ADDITIONS);
+
+ // Tooltip needs to be on top of other VOverlay elements.
+ setZIndex(VOverlay.Z_INDEX + 1);
}
/**
diff --git a/client/src/com/vaadin/client/connectors/AbstractSelectionModelConnector.java b/client/src/com/vaadin/client/connectors/AbstractSelectionModelConnector.java
new file mode 100644
index 0000000000..8ca2292bc5
--- /dev/null
+++ b/client/src/com/vaadin/client/connectors/AbstractSelectionModelConnector.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.client.connectors;
+
+import java.util.Collection;
+
+import com.vaadin.client.data.DataSource.RowHandle;
+import com.vaadin.client.extensions.AbstractExtensionConnector;
+import com.vaadin.client.widget.grid.selection.SelectionModel;
+import com.vaadin.client.widgets.Grid;
+import com.vaadin.shared.ui.grid.GridState;
+
+import elemental.json.JsonObject;
+
+/**
+ * Base class for all selection model connectors.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public abstract class AbstractSelectionModelConnector<T extends SelectionModel<JsonObject>>
+ extends AbstractExtensionConnector {
+
+ @Override
+ public GridConnector getParent() {
+ return (GridConnector) super.getParent();
+ }
+
+ protected Grid<JsonObject> getGrid() {
+ return getParent().getWidget();
+ }
+
+ protected RowHandle<JsonObject> getRowHandle(JsonObject row) {
+ return getGrid().getDataSource().getHandle(row);
+ }
+
+ protected String getRowKey(JsonObject row) {
+ return row != null ? getParent().getRowKey(row) : null;
+ }
+
+ protected abstract T createSelectionModel();
+
+ public abstract static class AbstractSelectionModel implements
+ SelectionModel<JsonObject> {
+
+ @Override
+ public boolean isSelected(JsonObject row) {
+ return row.hasKey(GridState.JSONKEY_SELECTED);
+ }
+
+ @Override
+ public void setGrid(Grid<JsonObject> grid) {
+ // NO-OP
+ }
+
+ @Override
+ public void reset() {
+ // Should not need any actions.
+ }
+
+ @Override
+ public Collection<JsonObject> getSelectedRows() {
+ throw new UnsupportedOperationException(
+ "This client-side selection model "
+ + getClass().getSimpleName()
+ + " does not know selected rows.");
+ }
+ }
+}
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java
index ef52a429e7..1070a46287 100644
--- a/client/src/com/vaadin/client/connectors/GridConnector.java
+++ b/client/src/com/vaadin/client/connectors/GridConnector.java
@@ -19,33 +19,36 @@ package com.vaadin.client.connectors;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.DeferredWorker;
import com.vaadin.client.MouseEventDetailsBuilder;
-import com.vaadin.client.annotations.OnStateChange;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.TooltipInfo;
import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
import com.vaadin.client.connectors.RpcDataSourceConnector.DetailsListener;
import com.vaadin.client.connectors.RpcDataSourceConnector.RpcDataSource;
-import com.vaadin.client.data.DataSource.RowHandle;
-import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.AbstractHasComponentsConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.CellStyleGenerator;
@@ -59,17 +62,12 @@ import com.vaadin.client.widget.grid.events.ColumnReorderEvent;
import com.vaadin.client.widget.grid.events.ColumnReorderHandler;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler;
+import com.vaadin.client.widget.grid.events.EditorCloseEvent;
+import com.vaadin.client.widget.grid.events.EditorEventHandler;
+import com.vaadin.client.widget.grid.events.EditorMoveEvent;
+import com.vaadin.client.widget.grid.events.EditorOpenEvent;
import com.vaadin.client.widget.grid.events.GridClickEvent;
import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
-import com.vaadin.client.widget.grid.events.SelectAllEvent;
-import com.vaadin.client.widget.grid.events.SelectAllHandler;
-import com.vaadin.client.widget.grid.selection.AbstractRowHandleSelectionModel;
-import com.vaadin.client.widget.grid.selection.SelectionEvent;
-import com.vaadin.client.widget.grid.selection.SelectionHandler;
-import com.vaadin.client.widget.grid.selection.SelectionModel;
-import com.vaadin.client.widget.grid.selection.SelectionModelMulti;
-import com.vaadin.client.widget.grid.selection.SelectionModelNone;
-import com.vaadin.client.widget.grid.selection.SelectionModelSingle;
import com.vaadin.client.widget.grid.sort.SortEvent;
import com.vaadin.client.widget.grid.sort.SortHandler;
import com.vaadin.client.widget.grid.sort.SortOrder;
@@ -79,10 +77,8 @@ import com.vaadin.client.widgets.Grid.FooterCell;
import com.vaadin.client.widgets.Grid.FooterRow;
import com.vaadin.client.widgets.Grid.HeaderCell;
import com.vaadin.client.widgets.Grid.HeaderRow;
-import com.vaadin.shared.Connector;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.grid.DetailsConnectorChange;
import com.vaadin.shared.ui.grid.EditorClientRpc;
import com.vaadin.shared.ui.grid.EditorServerRpc;
import com.vaadin.shared.ui.grid.GridClientRpc;
@@ -90,7 +86,6 @@ import com.vaadin.shared.ui.grid.GridColumnState;
import com.vaadin.shared.ui.grid.GridConstants;
import com.vaadin.shared.ui.grid.GridServerRpc;
import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode;
import com.vaadin.shared.ui.grid.GridStaticSectionState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState;
@@ -114,8 +109,8 @@ import elemental.json.JsonValue;
public class GridConnector extends AbstractHasComponentsConnector implements
SimpleManagedLayout, DeferredWorker {
- private static final class CustomCellStyleGenerator implements
- CellStyleGenerator<JsonObject> {
+ private static final class CustomStyleGenerator implements
+ CellStyleGenerator<JsonObject>, RowStyleGenerator<JsonObject> {
@Override
public String getStyle(CellReference<JsonObject> cellReference) {
JsonObject row = cellReference.getRow();
@@ -141,10 +136,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
}
- }
-
- private static final class CustomRowStyleGenerator implements
- RowStyleGenerator<JsonObject> {
@Override
public String getStyle(RowReference<JsonObject> rowReference) {
JsonObject row = rowReference.getRow();
@@ -154,7 +145,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
return null;
}
}
-
}
/**
@@ -169,6 +159,8 @@ public class GridConnector extends AbstractHasComponentsConnector implements
private AbstractFieldConnector editorConnector;
+ private HandlerRegistration errorStateHandler;
+
public CustomGridColumn(String id,
AbstractRendererConnector<Object> rendererConnector) {
super(rendererConnector.getRenderer());
@@ -205,8 +197,54 @@ public class GridConnector extends AbstractHasComponentsConnector implements
return editorConnector;
}
- private void setEditorConnector(AbstractFieldConnector editorConnector) {
+ private void setEditorConnector(
+ final AbstractFieldConnector editorConnector) {
this.editorConnector = editorConnector;
+
+ if (errorStateHandler != null) {
+ errorStateHandler.removeHandler();
+ errorStateHandler = null;
+ }
+
+ // Avoid nesting too deep
+ if (editorConnector == null) {
+ return;
+ }
+
+ errorStateHandler = editorConnector.addStateChangeHandler(
+ "errorMessage", new StateChangeHandler() {
+
+ @Override
+ public void onStateChanged(
+ StateChangeEvent stateChangeEvent) {
+
+ String error = editorConnector.getState().errorMessage;
+
+ if (error == null) {
+ columnToErrorMessage
+ .remove(CustomGridColumn.this);
+ } else {
+ // The error message is formatted as HTML;
+ // therefore, we use this hack to make the
+ // string human-readable.
+ Element e = DOM.createElement("div");
+ e.setInnerHTML(editorConnector.getState().errorMessage);
+ error = getHeaderCaption() + ": "
+ + e.getInnerText();
+
+ columnToErrorMessage.put(CustomGridColumn.this,
+ error);
+ }
+
+ // Editor should not be touched while there's a
+ // request pending.
+ if (editorHandler.currentRequest == null) {
+ getWidget().getEditor().setEditorError(
+ getColumnErrors(),
+ columnToErrorMessage.keySet());
+ }
+ }
+ });
}
}
@@ -281,7 +319,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements
if (column instanceof CustomGridColumn) {
AbstractFieldConnector c = ((CustomGridColumn) column)
.getEditorConnector();
- return c != null ? c.getWidget() : null;
+
+ if (c == null) {
+ return null;
+ }
+
+ return c.getWidget();
} else {
throw new IllegalStateException("Unexpected column type: "
+ column.getClass().getName());
@@ -420,255 +463,105 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
};
- private static class CustomDetailsGenerator implements DetailsGenerator {
+ private class CustomDetailsGenerator implements DetailsGenerator {
- private final Map<Integer, ComponentConnector> indexToDetailsMap = new HashMap<Integer, ComponentConnector>();
+ private final Map<String, ComponentConnector> idToDetailsMap = new HashMap<String, ComponentConnector>();
+ private final Map<String, Integer> idToRowIndex = new HashMap<String, Integer>();
@Override
- @SuppressWarnings("boxing")
public Widget getDetails(int rowIndex) {
- ComponentConnector componentConnector = indexToDetailsMap
- .get(rowIndex);
- if (componentConnector != null) {
- return componentConnector.getWidget();
- } else {
- return null;
- }
- }
-
- public void setDetailsConnectorChanges(
- Set<DetailsConnectorChange> changes) {
- /*
- * To avoid overwriting connectors while moving them about, we'll
- * take all the affected connectors, first all remove those that are
- * removed or moved, then we add back those that are moved or added.
- */
+ JsonObject row = getWidget().getDataSource().getRow(rowIndex);
- /* Remove moved/removed connectors from bookkeeping */
- for (DetailsConnectorChange change : changes) {
- Integer oldIndex = change.getOldIndex();
- Connector removedConnector = indexToDetailsMap.remove(oldIndex);
-
- Connector connector = change.getConnector();
- assert removedConnector == null || connector == null
- || removedConnector.equals(connector) : "Index "
- + oldIndex + " points to " + removedConnector
- + " while " + connector + " was expected";
+ if (!row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE)
+ || row.getString(GridState.JSONKEY_DETAILS_VISIBLE)
+ .isEmpty()) {
+ return null;
}
- /* Add moved/added connectors to bookkeeping */
- for (DetailsConnectorChange change : changes) {
- Integer newIndex = change.getNewIndex();
- ComponentConnector connector = (ComponentConnector) change
- .getConnector();
-
- if (connector != null) {
- assert newIndex != null : "An existing connector has a missing new index.";
-
- ComponentConnector prevConnector = indexToDetailsMap.put(
- newIndex, connector);
+ String id = row.getString(GridState.JSONKEY_DETAILS_VISIBLE);
+ ComponentConnector componentConnector = idToDetailsMap.get(id);
+ idToRowIndex.put(id, rowIndex);
- assert prevConnector == null : "Connector collision at index "
- + newIndex
- + " between old "
- + prevConnector
- + " and new " + connector;
- }
- }
+ return componentConnector.getWidget();
}
- }
-
- @SuppressWarnings("boxing")
- private static class DetailsConnectorFetcher implements DeferredWorker {
- private static final int FETCH_TIMEOUT_MS = 5000;
-
- public interface Listener {
- void fetchHasBeenScheduled(int id);
-
- void fetchHasReturned(int id);
- }
-
- /** A flag making sure that we don't call scheduleFinally many times. */
- private boolean fetcherHasBeenCalled = false;
-
- /** A rolling counter for unique values. */
- private int detailsFetchCounter = 0;
-
- /** A collection that tracks the amount of requests currently underway. */
- private Set<Integer> pendingFetches = new HashSet<Integer>(5);
-
- private final ScheduledCommand lazyDetailsFetcher = new ScheduledCommand() {
- @Override
- public void execute() {
- int currentFetchId = detailsFetchCounter++;
- pendingFetches.add(currentFetchId);
- rpc.sendDetailsComponents(currentFetchId);
- fetcherHasBeenCalled = false;
-
- if (listener != null) {
- listener.fetchHasBeenScheduled(currentFetchId);
+ public void updateConnectorHierarchy(List<ServerConnector> children) {
+ Set<String> connectorIds = new HashSet<String>();
+ for (ServerConnector child : children) {
+ if (child instanceof ComponentConnector) {
+ connectorIds.add(child.getConnectorId());
+ idToDetailsMap.put(child.getConnectorId(),
+ (ComponentConnector) child);
}
-
- assert assertRequestDoesNotTimeout(currentFetchId);
}
- };
-
- private DetailsConnectorFetcher.Listener listener = null;
-
- private final GridServerRpc rpc;
- public DetailsConnectorFetcher(GridServerRpc rpc) {
- assert rpc != null : "RPC was null";
- this.rpc = rpc;
- }
-
- public void schedule() {
- if (!fetcherHasBeenCalled) {
- Scheduler.get().scheduleFinally(lazyDetailsFetcher);
- fetcherHasBeenCalled = true;
- }
- }
-
- public void responseReceived(int fetchId) {
-
- if (fetchId < 0) {
- /* Ignore negative fetchIds (they're pushed, not fetched) */
- return;
+ Set<String> removedDetails = new HashSet<String>();
+ for (Entry<String, ComponentConnector> entry : idToDetailsMap
+ .entrySet()) {
+ ComponentConnector connector = entry.getValue();
+ String id = connector.getConnectorId();
+ if (!connectorIds.contains(id)) {
+ removedDetails.add(entry.getKey());
+ if (idToRowIndex.containsKey(id)) {
+ getWidget().setDetailsVisible(idToRowIndex.get(id),
+ false);
+ }
+ }
}
- boolean success = pendingFetches.remove(fetchId);
- assert success : "Received a response with an unidentified fetch id";
-
- if (listener != null) {
- listener.fetchHasReturned(fetchId);
+ for (String id : removedDetails) {
+ idToDetailsMap.remove(id);
+ idToRowIndex.remove(id);
}
}
-
- @Override
- public boolean isWorkPending() {
- return fetcherHasBeenCalled || !pendingFetches.isEmpty();
- }
-
- private boolean assertRequestDoesNotTimeout(final int fetchId) {
- /*
- * This method will not be compiled without asserts enabled. This
- * only makes sure that any request does not time out.
- *
- * TODO Should this be an explicit check? Is it worth the overhead?
- */
- new Timer() {
- @Override
- public void run() {
- assert !pendingFetches.contains(fetchId) : "Fetch id "
- + fetchId + " timed out.";
- }
- }.schedule(FETCH_TIMEOUT_MS);
- return true;
- }
-
- public void setListener(DetailsConnectorFetcher.Listener listener) {
- // if more are needed, feel free to convert this into a collection.
- this.listener = listener;
- }
}
/**
- * The functionality that makes sure that the scroll position is still kept
- * up-to-date even if more details are being fetched lazily.
+ * Class for handling scrolling issues with open details.
+ *
+ * @since 7.5.2
*/
- private class LazyDetailsScrollAdjuster implements DeferredWorker {
-
- private static final int SCROLL_TO_END_ID = -2;
- private static final int NO_SCROLL_SCHEDULED = -1;
-
- private class ScrollStopChecker implements DeferredWorker {
- private final ScheduledCommand checkCommand = new ScheduledCommand() {
- @Override
- public void execute() {
- isScheduled = false;
- if (queuedFetches.isEmpty()) {
- currentRow = NO_SCROLL_SCHEDULED;
- destination = null;
- }
- }
- };
-
- private boolean isScheduled = false;
-
- public void schedule() {
- if (isScheduled) {
- return;
- }
- Scheduler.get().scheduleDeferred(checkCommand);
- isScheduled = true;
- }
+ private class LazyDetailsScroller implements DeferredWorker {
- @Override
- public boolean isWorkPending() {
- return isScheduled;
- }
- }
+ /* Timer value tested to work in our test cluster with slow IE8s. */
+ private static final int DISABLE_LAZY_SCROLL_TIMEOUT = 1500;
- private DetailsConnectorFetcher.Listener fetcherListener = new DetailsConnectorFetcher.Listener() {
+ /*
+ * Cancels details opening scroll after timeout. Avoids any unexpected
+ * scrolls via details opening.
+ */
+ private Timer disableScroller = new Timer() {
@Override
- @SuppressWarnings("boxing")
- public void fetchHasBeenScheduled(int id) {
- if (currentRow != NO_SCROLL_SCHEDULED) {
- queuedFetches.add(id);
- }
- }
-
- @Override
- @SuppressWarnings("boxing")
- public void fetchHasReturned(int id) {
- if (currentRow == NO_SCROLL_SCHEDULED
- || queuedFetches.isEmpty()) {
- return;
- }
-
- queuedFetches.remove(id);
- if (currentRow == SCROLL_TO_END_ID) {
- getWidget().scrollToEnd();
- } else {
- getWidget().scrollToRow(currentRow, destination);
- }
-
- /*
- * Schedule a deferred call whether we should stop adjusting for
- * scrolling.
- *
- * This is done deferredly just because we can't be absolutely
- * certain whether this most recent scrolling won't cascade into
- * further lazy details loading (perhaps deferredly).
- */
- scrollStopChecker.schedule();
+ public void run() {
+ targetRow = -1;
}
};
- private int currentRow = NO_SCROLL_SCHEDULED;
- private final Set<Integer> queuedFetches = new HashSet<Integer>();
- private final ScrollStopChecker scrollStopChecker = new ScrollStopChecker();
- private ScrollDestination destination;
-
- public LazyDetailsScrollAdjuster() {
- detailsConnectorFetcher.setListener(fetcherListener);
- }
+ private Integer targetRow = -1;
+ private ScrollDestination destination = null;
- public void adjustForEnd() {
- currentRow = SCROLL_TO_END_ID;
+ public void scrollToRow(Integer row, ScrollDestination dest) {
+ targetRow = row;
+ destination = dest;
+ disableScroller.schedule(DISABLE_LAZY_SCROLL_TIMEOUT);
}
- public void adjustFor(int row, ScrollDestination destination) {
- currentRow = row;
- this.destination = destination;
+ /**
+ * Inform LazyDetailsScroller that a details row has opened on a row.
+ *
+ * @param rowIndex
+ * index of row with details now open
+ */
+ public void detailsOpened(int rowIndex) {
+ if (targetRow == rowIndex) {
+ getWidget().scrollToRow(targetRow, destination);
+ disableScroller.run();
+ }
}
@Override
public boolean isWorkPending() {
- return currentRow != NO_SCROLL_SCHEDULED
- || !queuedFetches.isEmpty()
- || scrollStopChecker.isWorkPending();
+ return disableScroller.isRunning();
}
}
@@ -677,20 +570,9 @@ public class GridConnector extends AbstractHasComponentsConnector implements
*/
private Map<String, CustomGridColumn> columnIdToColumn = new HashMap<String, CustomGridColumn>();
- private AbstractRowHandleSelectionModel<JsonObject> selectionModel;
- private Set<String> selectedKeys = new LinkedHashSet<String>();
private List<String> columnOrder = new ArrayList<String>();
/**
- * {@link #selectionUpdatedFromState} is set to true when
- * {@link #updateSelectionFromState()} makes changes to selection. This flag
- * tells the {@code internalSelectionChangeHandler} to not send same data
- * straight back to server. Said listener sets it back to false when
- * handling that event.
- */
- private boolean selectionUpdatedFromState;
-
- /**
* {@link #columnsUpdatedFromState} is set to true when
* {@link #updateColumnOrderFromState(List)} is updating the column order
* for the widget. This flag tells the {@link #columnReorderHandler} to not
@@ -701,68 +583,57 @@ public class GridConnector extends AbstractHasComponentsConnector implements
private RpcDataSource dataSource;
- private SelectionHandler<JsonObject> internalSelectionChangeHandler = new SelectionHandler<JsonObject>() {
- @Override
- public void onSelect(SelectionEvent<JsonObject> event) {
- if (event.isBatchedSelection()) {
- return;
- }
- if (!selectionUpdatedFromState) {
- for (JsonObject row : event.getRemoved()) {
- selectedKeys.remove(dataSource.getRowKey(row));
- }
-
- for (JsonObject row : event.getAdded()) {
- selectedKeys.add(dataSource.getRowKey(row));
- }
-
- getRpcProxy(GridServerRpc.class).select(
- new ArrayList<String>(selectedKeys));
- } else {
- selectionUpdatedFromState = false;
- }
- }
- };
+ /* Used to track Grid editor columns with validation errors */
+ private final Map<Column<?, JsonObject>, String> columnToErrorMessage = new HashMap<Column<?, JsonObject>, String>();
private ItemClickHandler itemClickHandler = new ItemClickHandler();
private String lastKnownTheme = null;
private final CustomDetailsGenerator customDetailsGenerator = new CustomDetailsGenerator();
-
- private final DetailsConnectorFetcher detailsConnectorFetcher = new DetailsConnectorFetcher(
- getRpcProxy(GridServerRpc.class));
+ private final CustomStyleGenerator styleGenerator = new CustomStyleGenerator();
private final DetailsListener detailsListener = new DetailsListener() {
@Override
public void reapplyDetailsVisibility(final int rowIndex,
final JsonObject row) {
- Scheduler.get().scheduleDeferred(new ScheduledCommand() {
- @Override
- public void execute() {
- if (hasDetailsOpen(row)) {
- getWidget().setDetailsVisible(rowIndex, true);
- detailsConnectorFetcher.schedule();
- } else {
+ if (hasDetailsOpen(row)) {
+ // Command for opening details row.
+ ScheduledCommand openDetails = new ScheduledCommand() {
+ @Override
+ public void execute() {
+ // Re-apply to force redraw.
getWidget().setDetailsVisible(rowIndex, false);
+ getWidget().setDetailsVisible(rowIndex, true);
+ lazyDetailsScroller.detailsOpened(rowIndex);
}
+ };
+
+ if (initialChange) {
+ Scheduler.get().scheduleDeferred(openDetails);
+ } else {
+ Scheduler.get().scheduleFinally(openDetails);
}
- });
+ } else {
+ getWidget().setDetailsVisible(rowIndex, false);
+ }
}
private boolean hasDetailsOpen(JsonObject row) {
return row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE)
- && row.getBoolean(GridState.JSONKEY_DETAILS_VISIBLE);
- }
-
- @Override
- public void closeDetails(int rowIndex) {
- getWidget().setDetailsVisible(rowIndex, false);
+ && row.getString(GridState.JSONKEY_DETAILS_VISIBLE) != null;
}
};
- private final LazyDetailsScrollAdjuster lazyDetailsScrollAdjuster = new LazyDetailsScrollAdjuster();
+ private final LazyDetailsScroller lazyDetailsScroller = new LazyDetailsScroller();
+ private final CustomEditorHandler editorHandler = new CustomEditorHandler();
+
+ /*
+ * Initially details need to behave a bit differently to allow some
+ * escalator magic.
+ */
+ private boolean initialChange;
@Override
@SuppressWarnings("unchecked")
@@ -797,11 +668,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements
@Override
public void scrollToEnd() {
- lazyDetailsScrollAdjuster.adjustForEnd();
Scheduler.get().scheduleFinally(new ScheduledCommand() {
@Override
public void execute() {
getWidget().scrollToEnd();
+ // Scrolls further if details opens.
+ lazyDetailsScroller.scrollToRow(dataSource.size() - 1,
+ ScrollDestination.END);
}
});
}
@@ -809,11 +682,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements
@Override
public void scrollToRow(final int row,
final ScrollDestination destination) {
- lazyDetailsScrollAdjuster.adjustFor(row, destination);
Scheduler.get().scheduleFinally(new ScheduledCommand() {
@Override
public void execute() {
getWidget().scrollToRow(row, destination);
+ // Scrolls a bit further if details opens.
+ lazyDetailsScroller.scrollToRow(row, destination);
}
});
}
@@ -822,59 +696,16 @@ public class GridConnector extends AbstractHasComponentsConnector implements
public void recalculateColumnWidths() {
getWidget().recalculateColumnWidths();
}
-
- @Override
- @SuppressWarnings("boxing")
- public void setDetailsConnectorChanges(
- Set<DetailsConnectorChange> connectorChanges, int fetchId) {
- customDetailsGenerator
- .setDetailsConnectorChanges(connectorChanges);
-
- List<DetailsConnectorChange> removedFirst = new ArrayList<DetailsConnectorChange>(
- connectorChanges);
- Collections.sort(removedFirst,
- DetailsConnectorChange.REMOVED_FIRST_COMPARATOR);
-
- // refresh moved/added details rows
- for (DetailsConnectorChange change : removedFirst) {
- Integer oldIndex = change.getOldIndex();
- Integer newIndex = change.getNewIndex();
-
- assert oldIndex == null || oldIndex >= 0 : "Got an "
- + "invalid old index: " + oldIndex
- + " (connector: " + change.getConnector() + ")";
- assert newIndex == null || newIndex >= 0 : "Got an "
- + "invalid new index: " + newIndex
- + " (connector: " + change.getConnector() + ")";
-
- if (oldIndex != null) {
- /* Close the old/removed index */
- getWidget().setDetailsVisible(oldIndex, false);
-
- if (change.isShouldStillBeVisible()) {
- getWidget().setDetailsVisible(oldIndex, true);
- }
- }
-
- if (newIndex != null) {
- /*
- * Since the component was lazy loaded, we need to
- * refresh the details by toggling it.
- */
- getWidget().setDetailsVisible(newIndex, false);
- getWidget().setDetailsVisible(newIndex, true);
- }
- }
- detailsConnectorFetcher.responseReceived(fetchId);
- }
});
- getWidget().addSelectionHandler(internalSelectionChangeHandler);
-
/* Item click events */
getWidget().addBodyClickHandler(itemClickHandler);
getWidget().addBodyDoubleClickHandler(itemClickHandler);
+ /* Style Generators */
+ getWidget().setCellStyleGenerator(styleGenerator);
+ getWidget().setRowStyleGenerator(styleGenerator);
+
getWidget().addSortHandler(new SortHandler<JsonObject>() {
@Override
public void sort(SortEvent<JsonObject> event) {
@@ -899,36 +730,51 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
});
- getWidget().addSelectAllHandler(new SelectAllHandler<JsonObject>() {
-
- @Override
- public void onSelectAll(SelectAllEvent<JsonObject> event) {
- getRpcProxy(GridServerRpc.class).selectAll();
- }
-
- });
-
- getWidget().setEditorHandler(new CustomEditorHandler());
+ getWidget().setEditorHandler(editorHandler);
getWidget().addColumnReorderHandler(columnReorderHandler);
getWidget().addColumnVisibilityChangeHandler(
columnVisibilityChangeHandler);
+
+ ConnectorFocusAndBlurHandler.addHandlers(this);
+
getWidget().setDetailsGenerator(customDetailsGenerator);
getLayoutManager().registerDependency(this, getWidget().getElement());
- layout();
- }
+ getWidget().addEditorEventHandler(new EditorEventHandler() {
+ @Override
+ public void onEditorOpen(EditorOpenEvent e) {
+ if (hasEventListener(GridConstants.EDITOR_OPEN_EVENT_ID)) {
+ String rowKey = getRowKey((JsonObject) e.getRow());
+ getRpcProxy(GridServerRpc.class).editorOpen(rowKey);
+ }
+ }
- @Override
- public void onUnregister() {
- customDetailsGenerator.indexToDetailsMap.clear();
+ @Override
+ public void onEditorMove(EditorMoveEvent e) {
+ if (hasEventListener(GridConstants.EDITOR_MOVE_EVENT_ID)) {
+ String rowKey = getRowKey((JsonObject) e.getRow());
+ getRpcProxy(GridServerRpc.class).editorMove(rowKey);
+ }
+ }
- super.onUnregister();
+ @Override
+ public void onEditorClose(EditorCloseEvent e) {
+ if (hasEventListener(GridConstants.EDITOR_CLOSE_EVENT_ID)) {
+ String rowKey = getRowKey((JsonObject) e.getRow());
+ getRpcProxy(GridServerRpc.class).editorClose(rowKey);
+ }
+ }
+ });
+
+ layout();
}
@Override
public void onStateChanged(final StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
+ initialChange = stateChangeEvent.isInitialStateChange();
+
// Column updates
if (stateChangeEvent.hasPropertyChanged("columns")) {
@@ -959,19 +805,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
updateFooterFromState(getState().footer);
}
- // Selection
- if (stateChangeEvent.hasPropertyChanged("selectionMode")) {
- onSelectionModeChange();
- updateSelectDeselectAllowed();
- } else if (stateChangeEvent
- .hasPropertyChanged("singleSelectDeselectAllowed")) {
- updateSelectDeselectAllowed();
- }
-
- if (stateChangeEvent.hasPropertyChanged("selectedKeys")) {
- updateSelectionFromState();
- }
-
// Sorting
if (stateChangeEvent.hasPropertyChanged("sortColumns")
|| stateChangeEvent.hasPropertyChanged("sortDirs")) {
@@ -998,14 +831,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
}
- private void updateSelectDeselectAllowed() {
- SelectionModel<JsonObject> model = getWidget().getSelectionModel();
- if (model instanceof SelectionModel.Single<?>) {
- ((SelectionModel.Single<?>) model)
- .setDeselectAllowed(getState().singleSelectDeselectAllowed);
- }
- }
-
private void updateColumnOrderFromState(List<String> stateColumnOrder) {
CustomGridColumn[] columns = new CustomGridColumn[stateColumnOrder
.size()];
@@ -1178,20 +1003,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
/**
- * If we have a selection column renderer, we need to offset the index by
- * one when referring to the column index in the widget.
- */
- private int getWidgetColumnIndex(final int columnIndex) {
- Renderer<Boolean> selectionColumnRenderer = getWidget()
- .getSelectionModel().getSelectionColumnRenderer();
- int widgetColumnIndex = columnIndex;
- if (selectionColumnRenderer != null) {
- widgetColumnIndex++;
- }
- return widgetColumnIndex;
- }
-
- /**
* Updates the column values from a state
*
* @param column
@@ -1253,81 +1064,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
getWidget().setDataSource(this.dataSource);
}
- private void onSelectionModeChange() {
- SharedSelectionMode mode = getState().selectionMode;
- if (mode == null) {
- getLogger().fine("ignored mode change");
- return;
- }
-
- AbstractRowHandleSelectionModel<JsonObject> model = createSelectionModel(mode);
- if (selectionModel == null
- || !model.getClass().equals(selectionModel.getClass())) {
- selectionModel = model;
- getWidget().setSelectionModel(model);
- selectedKeys.clear();
- }
- }
-
- @OnStateChange("hasCellStyleGenerator")
- private void onCellStyleGeneratorChange() {
- if (getState().hasCellStyleGenerator) {
- getWidget().setCellStyleGenerator(new CustomCellStyleGenerator());
- } else {
- getWidget().setCellStyleGenerator(null);
- }
- }
-
- @OnStateChange("hasRowStyleGenerator")
- private void onRowStyleGeneratorChange() {
- if (getState().hasRowStyleGenerator) {
- getWidget().setRowStyleGenerator(new CustomRowStyleGenerator());
- } else {
- getWidget().setRowStyleGenerator(null);
- }
- }
-
- private void updateSelectionFromState() {
- boolean changed = false;
-
- List<String> stateKeys = getState().selectedKeys;
-
- // find new deselections
- for (String key : selectedKeys) {
- if (!stateKeys.contains(key)) {
- changed = true;
- deselectByHandle(dataSource.getHandleByKey(key));
- }
- }
-
- // find new selections
- for (String key : stateKeys) {
- if (!selectedKeys.contains(key)) {
- changed = true;
- selectByHandle(dataSource.getHandleByKey(key));
- }
- }
-
- /*
- * A defensive copy in case the collection in the state is mutated
- * instead of re-assigned.
- */
- selectedKeys = new LinkedHashSet<String>(stateKeys);
-
- /*
- * We need to fire this event so that Grid is able to re-render the
- * selection changes (if applicable).
- */
- if (changed) {
- // At least for now there's no way to send the selected and/or
- // deselected row data. Some data is only stored as keys
- selectionUpdatedFromState = true;
- getWidget().fireEvent(
- new SelectionEvent<JsonObject>(getWidget(),
- (List<JsonObject>) null, null, false));
- }
- }
-
private void onSortStateChange() {
List<SortOrder> sortOrder = new ArrayList<SortOrder>();
@@ -1346,41 +1082,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements
return Logger.getLogger(getClass().getName());
}
- @SuppressWarnings("static-method")
- private AbstractRowHandleSelectionModel<JsonObject> createSelectionModel(
- SharedSelectionMode mode) {
- switch (mode) {
- case SINGLE:
- return new SelectionModelSingle<JsonObject>();
- case MULTI:
- return new SelectionModelMulti<JsonObject>();
- case NONE:
- return new SelectionModelNone<JsonObject>();
- default:
- throw new IllegalStateException("unexpected mode value: " + mode);
- }
- }
-
- /**
- * A workaround method for accessing the protected method
- * {@code AbstractRowHandleSelectionModel.selectByHandle}
- */
- private native void selectByHandle(RowHandle<JsonObject> handle)
- /*-{
- var model = this.@com.vaadin.client.connectors.GridConnector::selectionModel;
- model.@com.vaadin.client.widget.grid.selection.AbstractRowHandleSelectionModel::selectByHandle(*)(handle);
- }-*/;
-
- /**
- * A workaround method for accessing the protected method
- * {@code AbstractRowHandleSelectionModel.deselectByHandle}
- */
- private native void deselectByHandle(RowHandle<JsonObject> handle)
- /*-{
- var model = this.@com.vaadin.client.connectors.GridConnector::selectionModel;
- model.@com.vaadin.client.widget.grid.selection.AbstractRowHandleSelectionModel::deselectByHandle(*)(handle);
- }-*/;
-
/**
* Gets the row key for a row object.
*
@@ -1405,12 +1106,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements
@Override
public void updateCaption(ComponentConnector connector) {
// TODO Auto-generated method stub
-
}
@Override
public void onConnectorHierarchyChange(
ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) {
+ customDetailsGenerator.updateConnectorHierarchy(getChildren());
}
public String getColumnId(Grid.Column<?, ?> column) {
@@ -1427,8 +1128,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements
@Override
public boolean isWorkPending() {
- return detailsConnectorFetcher.isWorkPending()
- || lazyDetailsScrollAdjuster.isWorkPending();
+ return lazyDetailsScroller.isWorkPending();
}
/**
@@ -1441,4 +1141,74 @@ public class GridConnector extends AbstractHasComponentsConnector implements
public DetailsListener getDetailsListener() {
return detailsListener;
}
+
+ @Override
+ public boolean hasTooltip() {
+ return getState().hasDescriptions || super.hasTooltip();
+ }
+
+ @Override
+ public TooltipInfo getTooltipInfo(Element element) {
+ CellReference<JsonObject> cell = getWidget().getCellReference(element);
+
+ if (cell != null) {
+ JsonObject row = cell.getRow();
+ if (row == null) {
+ return null;
+ }
+
+ Column<?, JsonObject> column = cell.getColumn();
+ if (!(column instanceof CustomGridColumn)) {
+ // Selection checkbox column
+ return null;
+ }
+ CustomGridColumn c = (CustomGridColumn) column;
+
+ JsonObject cellDescriptions = row
+ .getObject(GridState.JSONKEY_CELLDESCRIPTION);
+
+ if (cellDescriptions != null && cellDescriptions.hasKey(c.id)) {
+ return new TooltipInfo(cellDescriptions.getString(c.id));
+ } else if (row.hasKey(GridState.JSONKEY_ROWDESCRIPTION)) {
+ return new TooltipInfo(
+ row.getString(GridState.JSONKEY_ROWDESCRIPTION));
+ } else {
+ return null;
+ }
+ }
+
+ return super.getTooltipInfo(element);
+ }
+
+ /**
+ * Creates a concatenation of all columns errors for Editor.
+ *
+ * @since
+ * @return displayed error string
+ */
+ private String getColumnErrors() {
+ List<String> errors = new ArrayList<String>();
+
+ for (Grid.Column<?, JsonObject> c : getWidget().getColumns()) {
+ if (!(c instanceof CustomGridColumn)) {
+ continue;
+ }
+
+ String error = columnToErrorMessage.get(c);
+ if (error != null) {
+ errors.add(error);
+ }
+ }
+
+ String result = "";
+ Iterator<String> i = errors.iterator();
+ while (i.hasNext()) {
+ result += i.next();
+ if (i.hasNext()) {
+ result += ", ";
+ }
+ }
+ return result.isEmpty() ? null : result;
+ }
+
}
diff --git a/client/src/com/vaadin/client/connectors/MultiSelectionModelConnector.java b/client/src/com/vaadin/client/connectors/MultiSelectionModelConnector.java
new file mode 100644
index 0000000000..e4ad50e7ac
--- /dev/null
+++ b/client/src/com/vaadin/client/connectors/MultiSelectionModelConnector.java
@@ -0,0 +1,383 @@
+/*
+ * 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.connectors;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.annotations.OnStateChange;
+import com.vaadin.client.data.DataSource;
+import com.vaadin.client.data.DataSource.RowHandle;
+import com.vaadin.client.renderers.ComplexRenderer;
+import com.vaadin.client.renderers.Renderer;
+import com.vaadin.client.widget.grid.DataAvailableEvent;
+import com.vaadin.client.widget.grid.DataAvailableHandler;
+import com.vaadin.client.widget.grid.events.SelectAllEvent;
+import com.vaadin.client.widget.grid.events.SelectAllHandler;
+import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
+import com.vaadin.client.widget.grid.selection.SelectionModel;
+import com.vaadin.client.widget.grid.selection.SelectionModel.Multi;
+import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
+import com.vaadin.client.widgets.Grid;
+import com.vaadin.client.widgets.Grid.HeaderCell;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.GridState;
+import com.vaadin.shared.ui.grid.Range;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
+import com.vaadin.ui.Grid.MultiSelectionModel;
+
+import elemental.json.JsonObject;
+
+/**
+ * Connector for server-side {@link MultiSelectionModel}.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@Connect(MultiSelectionModel.class)
+public class MultiSelectionModelConnector extends
+ AbstractSelectionModelConnector<SelectionModel.Multi<JsonObject>> {
+
+ private Multi<JsonObject> selectionModel = createSelectionModel();
+ private SpaceSelectHandler<JsonObject> spaceHandler;
+
+ @Override
+ protected void extend(ServerConnector target) {
+ getGrid().setSelectionModel(selectionModel);
+ spaceHandler = new SpaceSelectHandler<JsonObject>(getGrid());
+ }
+
+ @Override
+ public void onUnregister() {
+ spaceHandler.removeHandler();
+ }
+
+ @Override
+ protected Multi<JsonObject> createSelectionModel() {
+ return new MultiSelectionModel();
+ }
+
+ @Override
+ public MultiSelectionModelState getState() {
+ return (MultiSelectionModelState) super.getState();
+ }
+
+ @OnStateChange("allSelected")
+ void updateSelectAllCheckbox() {
+ if (selectionModel.getSelectionColumnRenderer() != null) {
+ HeaderCell cell = getGrid().getDefaultHeaderRow().getCell(
+ getGrid().getColumn(0));
+ CheckBox widget = (CheckBox) cell.getWidget();
+ widget.setValue(getState().allSelected, false);
+ }
+ }
+
+ protected class MultiSelectionModel extends AbstractSelectionModel
+ implements SelectionModel.Multi.Batched<JsonObject> {
+
+ private ComplexRenderer<Boolean> renderer = null;
+ private Set<RowHandle<JsonObject>> selected = new HashSet<RowHandle<JsonObject>>();
+ private Set<RowHandle<JsonObject>> deselected = new HashSet<RowHandle<JsonObject>>();
+ private HandlerRegistration selectAll;
+ private HandlerRegistration dataAvailable;
+ private Range availableRows;
+ private boolean batchSelect = false;
+
+ @Override
+ public void setGrid(Grid<JsonObject> grid) {
+ super.setGrid(grid);
+ if (grid != null) {
+ renderer = createSelectionColumnRenderer(grid);
+ selectAll = getGrid().addSelectAllHandler(
+ new SelectAllHandler<JsonObject>() {
+
+ @Override
+ public void onSelectAll(
+ SelectAllEvent<JsonObject> event) {
+ selectAll();
+ }
+ });
+ dataAvailable = getGrid().addDataAvailableHandler(
+ new DataAvailableHandler() {
+
+ @Override
+ public void onDataAvailable(DataAvailableEvent event) {
+ availableRows = event.getAvailableRows();
+ }
+ });
+ } else if (renderer != null) {
+ renderer.destroy();
+ selectAll.removeHandler();
+ dataAvailable.removeHandler();
+ renderer = null;
+ }
+ }
+
+ /**
+ * Creates a selection column renderer. This method can be overridden to
+ * use a custom renderer or use {@code null} to disable the selection
+ * column.
+ *
+ * @param grid
+ * the grid for this selection model
+ * @return selection column renderer or {@code null} if not needed
+ */
+ protected ComplexRenderer<Boolean> createSelectionColumnRenderer(
+ Grid<JsonObject> grid) {
+ return new MultiSelectionRenderer<JsonObject>(grid);
+ }
+
+ /**
+ * Selects all available rows, sends request to server to select
+ * everything.
+ */
+ public void selectAll() {
+ assert !isBeingBatchSelected() : "Can't select all in middle of a batch selection.";
+
+ DataSource<JsonObject> dataSource = getGrid().getDataSource();
+ for (int i = availableRows.getStart(); i < availableRows.getEnd(); ++i) {
+ final JsonObject row = dataSource.getRow(i);
+ if (row != null) {
+ RowHandle<JsonObject> handle = dataSource.getHandle(row);
+ markAsSelected(handle, true);
+ }
+ }
+
+ getRpcProxy(MultiSelectionModelServerRpc.class).selectAll();
+ }
+
+ @Override
+ public Renderer<Boolean> getSelectionColumnRenderer() {
+ return renderer;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@code false} if rows is empty, else {@code true}
+ */
+ @Override
+ public boolean select(JsonObject... rows) {
+ return select(Arrays.asList(rows));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@code false} if rows is empty, else {@code true}
+ */
+ @Override
+ public boolean deselect(JsonObject... rows) {
+ return deselect(Arrays.asList(rows));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return always {@code true}
+ */
+ @Override
+ public boolean deselectAll() {
+ assert !isBeingBatchSelected() : "Can't select all in middle of a batch selection.";
+
+ DataSource<JsonObject> dataSource = getGrid().getDataSource();
+ for (int i = availableRows.getStart(); i < availableRows.getEnd(); ++i) {
+ final JsonObject row = dataSource.getRow(i);
+ if (row != null) {
+ RowHandle<JsonObject> handle = dataSource.getHandle(row);
+ markAsSelected(handle, false);
+ }
+ }
+
+ getRpcProxy(MultiSelectionModelServerRpc.class).deselectAll();
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@code false} if rows is empty, else {@code true}
+ */
+ @Override
+ public boolean select(Collection<JsonObject> rows) {
+ if (rows.isEmpty()) {
+ return false;
+ }
+
+ for (JsonObject row : rows) {
+ RowHandle<JsonObject> rowHandle = getRowHandle(row);
+ if (markAsSelected(rowHandle, true)) {
+ selected.add(rowHandle);
+ }
+ }
+
+ if (!isBeingBatchSelected()) {
+ sendSelected();
+ }
+ return true;
+ }
+
+ /**
+ * Marks the given row to be selected or deselected. Returns true if the
+ * value actually changed.
+ * <p>
+ * Note: If selection model is in batch select state, the row will be
+ * pinned on select.
+ *
+ * @param row
+ * row handle
+ * @param selected
+ * {@code true} if row should be selected; {@code false} if
+ * not
+ * @return {@code true} if selected status changed; {@code false} if not
+ */
+ protected boolean markAsSelected(RowHandle<JsonObject> row,
+ boolean selected) {
+ if (selected && !isSelected(row.getRow())) {
+ row.getRow().put(GridState.JSONKEY_SELECTED, true);
+ } else if (!selected && isSelected(row.getRow())) {
+ row.getRow().remove(GridState.JSONKEY_SELECTED);
+ } else {
+ return false;
+ }
+
+ row.updateRow();
+
+ if (isBeingBatchSelected()) {
+ row.pin();
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@code false} if rows is empty, else {@code true}
+ */
+ @Override
+ public boolean deselect(Collection<JsonObject> rows) {
+ if (rows.isEmpty()) {
+ return false;
+ }
+
+ for (JsonObject row : rows) {
+ RowHandle<JsonObject> rowHandle = getRowHandle(row);
+ if (markAsSelected(rowHandle, false)) {
+ deselected.add(rowHandle);
+ }
+ }
+
+ if (!isBeingBatchSelected()) {
+ sendDeselected();
+ }
+ return true;
+ }
+
+ /**
+ * Sends a deselect RPC call to server-side containing all deselected
+ * rows. Unpins any pinned rows.
+ */
+ private void sendDeselected() {
+ getRpcProxy(MultiSelectionModelServerRpc.class).deselect(
+ getRowKeys(deselected));
+
+ if (isBeingBatchSelected()) {
+ for (RowHandle<JsonObject> row : deselected) {
+ row.unpin();
+ }
+ }
+
+ deselected.clear();
+ }
+
+ /**
+ * Sends a select RPC call to server-side containing all selected rows.
+ * Unpins any pinned rows.
+ */
+ private void sendSelected() {
+ getRpcProxy(MultiSelectionModelServerRpc.class).select(
+ getRowKeys(selected));
+
+ if (isBeingBatchSelected()) {
+ for (RowHandle<JsonObject> row : selected) {
+ row.unpin();
+ }
+ }
+
+ selected.clear();
+ }
+
+ private List<String> getRowKeys(Set<RowHandle<JsonObject>> handles) {
+ List<String> keys = new ArrayList<String>();
+ for (RowHandle<JsonObject> handle : handles) {
+ keys.add(getRowKey(handle.getRow()));
+ }
+ return keys;
+ }
+
+ private Set<JsonObject> getRows(Set<RowHandle<JsonObject>> handles) {
+ Set<JsonObject> rows = new HashSet<JsonObject>();
+ for (RowHandle<JsonObject> handle : handles) {
+ rows.add(handle.getRow());
+ }
+ return rows;
+ }
+
+ @Override
+ public void startBatchSelect() {
+ assert selected.isEmpty() && deselected.isEmpty() : "Row caches were not clear.";
+ batchSelect = true;
+ }
+
+ @Override
+ public void commitBatchSelect() {
+ assert batchSelect : "Not batch selecting.";
+ if (!selected.isEmpty()) {
+ sendSelected();
+ }
+
+ if (!deselected.isEmpty()) {
+ sendDeselected();
+ }
+ batchSelect = false;
+ }
+
+ @Override
+ public boolean isBeingBatchSelected() {
+ return batchSelect;
+ }
+
+ @Override
+ public Collection<JsonObject> getSelectedRowsBatch() {
+ return Collections.unmodifiableSet(getRows(selected));
+ }
+
+ @Override
+ public Collection<JsonObject> getDeselectedRowsBatch() {
+ return Collections.unmodifiableSet(getRows(deselected));
+ }
+ }
+}
diff --git a/client/src/com/vaadin/client/connectors/NoSelectionModelConnector.java b/client/src/com/vaadin/client/connectors/NoSelectionModelConnector.java
new file mode 100644
index 0000000000..b540eed6d5
--- /dev/null
+++ b/client/src/com/vaadin/client/connectors/NoSelectionModelConnector.java
@@ -0,0 +1,42 @@
+/*
+ * 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.connectors;
+
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.widget.grid.selection.SelectionModel;
+import com.vaadin.client.widget.grid.selection.SelectionModelNone;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.ui.Grid.NoSelectionModel;
+
+import elemental.json.JsonObject;
+
+/**
+ * Connector for server-side {@link NoSelectionModel}.
+ */
+@Connect(NoSelectionModel.class)
+public class NoSelectionModelConnector extends
+ AbstractSelectionModelConnector<SelectionModel<JsonObject>> {
+
+ @Override
+ protected void extend(ServerConnector target) {
+ getGrid().setSelectionModel(createSelectionModel());
+ }
+
+ @Override
+ protected SelectionModel<JsonObject> createSelectionModel() {
+ return new SelectionModelNone<JsonObject>();
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
index 627ee74eca..5daa02c3bf 100644
--- a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
+++ b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java
@@ -17,6 +17,7 @@
package com.vaadin.client.connectors;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import com.vaadin.client.ServerConnector;
@@ -64,14 +65,6 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
* @see GridState#JSONKEY_DETAILS_VISIBLE
*/
void reapplyDetailsVisibility(int rowIndex, JsonObject row);
-
- /**
- * Closes details for a row.
- *
- * @param rowIndex
- * the index of the row for which to close details
- */
- void closeDetails(int rowIndex);
}
public class RpcDataSource extends AbstractRemoteDataSource<JsonObject> {
@@ -104,15 +97,28 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
public void resetDataAndSize(int size) {
RpcDataSource.this.resetDataAndSize(size);
}
+
+ @Override
+ public void updateRowData(JsonArray rowArray) {
+ for (int i = 0; i < rowArray.length(); ++i) {
+ RpcDataSource.this.updateRowData(rowArray.getObject(i));
+ }
+ }
});
}
private DataRequestRpc rpcProxy = getRpcProxy(DataRequestRpc.class);
private DetailsListener detailsListener;
+ private JsonArray droppedRowKeys = Json.createArray();
@Override
protected void requestRows(int firstRowIndex, int numberOfRows,
RequestRowsCallback<JsonObject> callback) {
+ if (droppedRowKeys.length() > 0) {
+ rpcProxy.dropRows(droppedRowKeys);
+ droppedRowKeys = Json.createArray();
+ }
+
/*
* If you're looking at this code because you want to learn how to
* use AbstactRemoteDataSource, please look somewhere else instead.
@@ -184,23 +190,15 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
}
@Override
- protected void pinHandle(RowHandleImpl handle) {
- // Server only knows if something is pinned or not. No need to pin
- // multiple times.
- boolean pinnedBefore = handle.isPinned();
- super.pinHandle(handle);
- if (!pinnedBefore) {
- rpcProxy.setPinned(getRowKey(handle.getRow()), true);
- }
- }
-
- @Override
protected void unpinHandle(RowHandleImpl handle) {
// Row data is no longer available after it has been unpinned.
String key = getRowKey(handle.getRow());
super.unpinHandle(handle);
if (!handle.isPinned()) {
- rpcProxy.setPinned(key, false);
+ if (indexOfKey(key) == -1) {
+ // Row out of view has been unpinned. drop it
+ droppedRowKeys.set(droppedRowKeys.length(), key);
+ }
}
}
@@ -222,9 +220,25 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector {
}
}
+ /**
+ * Updates row data based on row key.
+ *
+ * @since 7.6
+ * @param row
+ * new row object
+ */
+ protected void updateRowData(JsonObject row) {
+ int index = indexOfKey(getRowKey(row));
+ if (index >= 0) {
+ setRowData(index, Collections.singletonList(row));
+ }
+ }
+
@Override
- protected void onDropFromCache(int rowIndex) {
- detailsListener.closeDetails(rowIndex);
+ protected void onDropFromCache(int rowIndex, JsonObject row) {
+ if (!((RowHandleImpl) getHandle(row)).isPinned()) {
+ droppedRowKeys.set(droppedRowKeys.length(), getRowKey(row));
+ }
}
}
diff --git a/client/src/com/vaadin/client/connectors/SingleSelectionModelConnector.java b/client/src/com/vaadin/client/connectors/SingleSelectionModelConnector.java
new file mode 100644
index 0000000000..7c66903c2c
--- /dev/null
+++ b/client/src/com/vaadin/client/connectors/SingleSelectionModelConnector.java
@@ -0,0 +1,148 @@
+/*
+ * 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.connectors;
+
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.annotations.OnStateChange;
+import com.vaadin.client.data.DataSource.RowHandle;
+import com.vaadin.client.renderers.Renderer;
+import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
+import com.vaadin.client.widget.grid.selection.SelectionModel;
+import com.vaadin.client.widget.grid.selection.SelectionModel.Single;
+import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.GridState;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelState;
+import com.vaadin.ui.Grid.SingleSelectionModel;
+
+import elemental.json.JsonObject;
+
+/**
+ * Connector for server-side {@link SingleSelectionModel}.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@Connect(SingleSelectionModel.class)
+public class SingleSelectionModelConnector extends
+ AbstractSelectionModelConnector<SelectionModel.Single<JsonObject>> {
+
+ private SpaceSelectHandler<JsonObject> spaceHandler;
+ private ClickSelectHandler<JsonObject> clickHandler;
+ private Single<JsonObject> selectionModel = createSelectionModel();
+
+ @Override
+ protected void extend(ServerConnector target) {
+ getGrid().setSelectionModel(selectionModel);
+ spaceHandler = new SpaceSelectHandler<JsonObject>(getGrid());
+ clickHandler = new ClickSelectHandler<JsonObject>(getGrid());
+ }
+
+ @Override
+ public SingleSelectionModelState getState() {
+ return (SingleSelectionModelState) super.getState();
+ }
+
+ @Override
+ public void onUnregister() {
+ spaceHandler.removeHandler();
+ clickHandler.removeHandler();
+
+ super.onUnregister();
+ }
+
+ @Override
+ protected Single<JsonObject> createSelectionModel() {
+ return new SingleSelectionModel();
+ }
+
+ @OnStateChange("deselectAllowed")
+ void updateDeselectAllowed() {
+ selectionModel.setDeselectAllowed(getState().deselectAllowed);
+ }
+
+ /**
+ * SingleSelectionModel without a selection column renderer.
+ */
+ public class SingleSelectionModel extends AbstractSelectionModel implements
+ SelectionModel.Single<JsonObject> {
+
+ private RowHandle<JsonObject> selectedRow;
+ private boolean deselectAllowed;
+
+ @Override
+ public Renderer<Boolean> getSelectionColumnRenderer() {
+ return null;
+ }
+
+ @Override
+ public boolean select(JsonObject row) {
+ boolean changed = false;
+ if ((row == null && isDeselectAllowed())
+ || (row != null && !getRowHandle(row).equals(selectedRow))) {
+ if (selectedRow != null) {
+ selectedRow.getRow().remove(GridState.JSONKEY_SELECTED);
+ selectedRow.updateRow();
+ selectedRow.unpin();
+ selectedRow = null;
+ changed = true;
+ }
+
+ if (row != null) {
+ selectedRow = getRowHandle(row);
+ selectedRow.pin();
+ selectedRow.getRow().put(GridState.JSONKEY_SELECTED, true);
+ selectedRow.updateRow();
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ getRpcProxy(SingleSelectionModelServerRpc.class).select(
+ getRowKey(row));
+ }
+
+ return changed;
+ }
+
+ @Override
+ public boolean deselect(JsonObject row) {
+ if (getRowHandle(row).equals(selectedRow)) {
+ select(null);
+ }
+ return false;
+ }
+
+ @Override
+ public JsonObject getSelectedRow() {
+ throw new UnsupportedOperationException(
+ "This client-side selection model "
+ + getClass().getSimpleName()
+ + " does not know selected row.");
+ }
+
+ @Override
+ public void setDeselectAllowed(boolean deselectAllowed) {
+ this.deselectAllowed = deselectAllowed;
+ }
+
+ @Override
+ public boolean isDeselectAllowed() {
+ return deselectAllowed;
+ }
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
index 459127c9b4..58cd5c5f19 100644
--- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
+++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java
@@ -16,8 +16,6 @@
package com.vaadin.client.data;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -120,12 +118,7 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
@Override
public T getRow() throws IllegalStateException {
- if (isPinned()) {
- return row;
- } else {
- throw new IllegalStateException("The row handle for key " + key
- + " was not pinned");
- }
+ return row;
}
public boolean isPinned() {
@@ -197,7 +190,6 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
private Map<Object, Integer> pinnedCounts = new HashMap<Object, Integer>();
private Map<Object, RowHandleImpl> pinnedRows = new HashMap<Object, RowHandleImpl>();
- protected Collection<T> temporarilyPinnedRows = Collections.emptySet();
// Size not yet known
private int size = -1;
@@ -287,8 +279,7 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
* Simple case: no overlap between cached data and needed data.
* Clear the cache and request new data
*/
- indexToRowMap.clear();
- keyToIndexMap.clear();
+ dropFromCache(cached);
cached = Range.between(0, 0);
handleMissingRows(getMaxCacheRange());
@@ -330,25 +321,48 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
private void dropFromCache(Range range) {
for (int i = range.getStart(); i < range.getEnd(); i++) {
+ // Called after dropping from cache. Dropped row is passed as a
+ // parameter, but is no longer present in the DataSource
T removed = indexToRowMap.remove(Integer.valueOf(i));
+ onDropFromCache(i, removed);
keyToIndexMap.remove(getRowKey(removed));
-
- onDropFromCache(i);
}
}
/**
- * A hook that can be overridden to do something whenever a row is dropped
- * from the cache.
+ * A hook that can be overridden to do something whenever a row has been
+ * dropped from the cache. DataSource no longer has anything in the given
+ * index.
+ * <p>
+ * NOTE: This method has been replaced. Override
+ * {@link #onDropFromCache(int, Object)} instead of this method.
*
* @since 7.5.0
* @param rowIndex
* the index of the dropped row
+ * @deprecated replaced by {@link #onDropFromCache(int, Object)}
*/
+ @Deprecated
protected void onDropFromCache(int rowIndex) {
// noop
}
+ /**
+ * A hook that can be overridden to do something whenever a row has been
+ * dropped from the cache. DataSource no longer has anything in the given
+ * index.
+ *
+ * @since 7.6
+ * @param rowIndex
+ * the index of the dropped row
+ * @param removed
+ * the removed row object
+ */
+ protected void onDropFromCache(int rowIndex, T removed) {
+ // Call old version as a fallback (someone might have used it)
+ onDropFromCache(rowIndex);
+ }
+
private void handleMissingRows(Range range) {
if (range.isEmpty()) {
return;
@@ -479,6 +493,15 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
* updated before the widget settings. Support for this will be
* implemented later on.
*/
+
+ // Run a dummy drop from cache for unused rows.
+ for (int i = 0; i < partition[0].length(); ++i) {
+ onDropFromCache(i + partition[0].getStart(), rowData.get(i));
+ }
+
+ for (int i = 0; i < partition[2].length(); ++i) {
+ onDropFromCache(i + partition[2].getStart(), rowData.get(i));
+ }
}
// Eventually check whether all needed rows are now available
@@ -732,4 +755,12 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
dataChangeHandler.resetDataAndSize(newSize);
}
}
+
+ protected int indexOfKey(Object rowKey) {
+ if (!keyToIndexMap.containsKey(rowKey)) {
+ return -1;
+ } else {
+ return keyToIndexMap.get(rowKey);
+ }
+ }
}
diff --git a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java
index b543c23e4d..fbc838f861 100644
--- a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java
+++ b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java
@@ -19,6 +19,8 @@ import java.util.ArrayList;
import java.util.Date;
import com.google.gwt.core.client.Duration;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -698,22 +700,32 @@ public final class VDebugWindow extends VOverlay {
public void init() {
show();
- readStoredState();
- Window.addResizeHandler(new com.google.gwt.event.logical.shared.ResizeHandler() {
+ /*
+ * Finalize initialization when all entry points have had the chance to
+ * e.g. register new sections.
+ */
+ Scheduler.get().scheduleFinally(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ readStoredState();
- Timer t = new Timer() {
- @Override
- public void run() {
- applyPositionAndSize();
- }
- };
+ Window.addResizeHandler(new com.google.gwt.event.logical.shared.ResizeHandler() {
- @Override
- public void onResize(ResizeEvent event) {
- t.cancel();
- // TODO less
- t.schedule(1000);
+ Timer t = new Timer() {
+ @Override
+ public void run() {
+ applyPositionAndSize();
+ }
+ };
+
+ @Override
+ public void onResize(ResizeEvent event) {
+ t.cancel();
+ // TODO less
+ t.schedule(1000);
+ }
+ });
}
});
}
diff --git a/client/src/com/vaadin/client/extensions/ResponsiveConnector.java b/client/src/com/vaadin/client/extensions/ResponsiveConnector.java
index 621c69788c..ae330be8f4 100644
--- a/client/src/com/vaadin/client/extensions/ResponsiveConnector.java
+++ b/client/src/com/vaadin/client/extensions/ResponsiveConnector.java
@@ -205,7 +205,7 @@ public class ResponsiveConnector extends AbstractExtensionConnector implements
// Get all the rulesets from the stylesheet
var theRules = new Array();
- var IE = @com.vaadin.client.BrowserInfo::get()().@com.vaadin.client.BrowserInfo::isIE()();
+ var IEOrEdge = @com.vaadin.client.BrowserInfo::get()().@com.vaadin.client.BrowserInfo::isIE()() || @com.vaadin.client.BrowserInfo::get()().@com.vaadin.client.BrowserInfo::isEdge()();
var IE8 = @com.vaadin.client.BrowserInfo::get()().@com.vaadin.client.BrowserInfo::isIE8()();
try {
@@ -263,8 +263,8 @@ public class ResponsiveConnector extends AbstractExtensionConnector implements
// Array of all of the separate selectors in this ruleset
var haystack = rule.selectorText.split(",");
- // IE parses CSS like .class[attr="val"] into [attr="val"].class so we need to check for both
- var selectorRegEx = IE ? /\[.*\]([\.|#]\S+)/ : /([\.|#]\S+?)\[.*\]/;
+ // IE/Edge parses CSS like .class[attr="val"] into [attr="val"].class so we need to check for both
+ var selectorRegEx = IEOrEdge ? /\[.*\]([\.|#]\S+)/ : /([\.|#]\S+?)\[.*\]/;
// Loop all the selectors in this ruleset
for(var k = 0, len2 = haystack.length; k < len2; k++) {
diff --git a/client/src/com/vaadin/client/ui/AbstractConnector.java b/client/src/com/vaadin/client/ui/AbstractConnector.java
index a20c3463c2..7f8d6c2b14 100644
--- a/client/src/com/vaadin/client/ui/AbstractConnector.java
+++ b/client/src/com/vaadin/client/ui/AbstractConnector.java
@@ -25,7 +25,7 @@ import java.util.Set;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
-import com.google.web.bindery.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HandlerRegistration;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.FastStringMap;
import com.vaadin.client.FastStringSet;
diff --git a/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java
new file mode 100644
index 0000000000..8272f99d25
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java
@@ -0,0 +1,87 @@
+/*
+ * 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.ui;
+
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.EventHelper;
+import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.shared.EventId;
+import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
+
+/**
+ * A handler for focus and blur events which uses {@link FocusAndBlurServerRpc}
+ * to transmit received events to the server. Events are only handled if there
+ * is a corresponding listener on the server side.
+ *
+ * @since 7.6
+ * @author Vaadin Ltd
+ */
+public class ConnectorFocusAndBlurHandler implements StateChangeHandler,
+ FocusHandler, BlurHandler {
+
+ private final AbstractComponentConnector connector;
+ private final Widget widget;
+ private HandlerRegistration focusRegistration = null;
+ private HandlerRegistration blurRegistration = null;
+
+ public static void addHandlers(AbstractComponentConnector connector) {
+ addHandlers(connector, connector.getWidget());
+ }
+
+ public static void addHandlers(AbstractComponentConnector connector,
+ Widget widget) {
+ connector.addStateChangeHandler("registeredEventListeners",
+ new ConnectorFocusAndBlurHandler(connector, widget));
+ }
+
+ private ConnectorFocusAndBlurHandler(AbstractComponentConnector connector,
+ Widget widget) {
+ this.connector = connector;
+ this.widget = widget;
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ focusRegistration = EventHelper.updateHandler(connector, this,
+ EventId.FOCUS, focusRegistration, FocusEvent.getType(), widget);
+ blurRegistration = EventHelper.updateHandler(connector, this,
+ EventId.BLUR, blurRegistration, BlurEvent.getType(), widget);
+ }
+
+ @Override
+ public void onFocus(FocusEvent event) {
+ // updateHandler ensures that this is called only when
+ // there is a listener on the server side
+ getRpc().focus();
+ }
+
+ @Override
+ public void onBlur(BlurEvent event) {
+ // updateHandler ensures that this is called only when
+ // there is a listener on the server side
+ getRpc().blur();
+ }
+
+ private FocusAndBlurServerRpc getRpc() {
+ return connector.getRpcProxy(FocusAndBlurServerRpc.class);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java
index 9dd9c17675..1ac5a08ccd 100644
--- a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java
+++ b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java
@@ -74,7 +74,7 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
style.setPosition(Position.FIXED);
style.setTop(0, Unit.PX);
style.setLeft(0, Unit.PX);
- if (browserInfo.isIE()) {
+ if (browserInfo.isIE() || browserInfo.isEdge()) {
// for #15294: artificially hide little bit more the
// focusElement, otherwise IE will make the window to scroll
// into it when focused
diff --git a/client/src/com/vaadin/client/ui/VButton.java b/client/src/com/vaadin/client/ui/VButton.java
index bf321f7f00..2eb967c4fa 100644
--- a/client/src/com/vaadin/client/ui/VButton.java
+++ b/client/src/com/vaadin/client/ui/VButton.java
@@ -23,7 +23,6 @@ import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FocusWidget;
@@ -94,8 +93,6 @@ public class VButton extends FocusWidget implements ClickHandler {
/** For internal use only. May be removed or replaced in the future. */
public int clickShortcut = 0;
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
private long lastClickTime = 0;
public VButton() {
diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java
index 7951759fa2..cf03382333 100644
--- a/client/src/com/vaadin/client/ui/VFilterSelect.java
+++ b/client/src/com/vaadin/client/ui/VFilterSelect.java
@@ -65,6 +65,7 @@ import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ComputedStyle;
import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.DeferredWorker;
import com.vaadin.client.Focusable;
import com.vaadin.client.UIDL;
import com.vaadin.client.VConsole;
@@ -90,7 +91,7 @@ import com.vaadin.shared.util.SharedUtil;
public class VFilterSelect extends Composite implements Field, KeyDownHandler,
KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable,
SubPartAware, HandlesAriaCaption, HandlesAriaInvalid,
- HandlesAriaRequired {
+ HandlesAriaRequired, DeferredWorker {
/**
* Represents a suggestion in the suggestion popup box
@@ -417,7 +418,9 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
selectPrevPage();
} else {
- selectItem(menu.getItems().get(menu.getItems().size() - 1));
+ if (!menu.getItems().isEmpty()) {
+ selectLastItem();
+ }
}
}
@@ -596,7 +599,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
+ "]");
Element menuFirstChild = menu.getElement().getFirstChildElement();
- final int naturalMenuWidth = menuFirstChild.getOffsetWidth();
+ final int naturalMenuWidth = WidgetUtil
+ .getRequiredWidth(menuFirstChild);
if (popupOuterPadding == -1) {
popupOuterPadding = WidgetUtil
@@ -608,13 +612,21 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
menuFirstChild.getStyle().setWidth(100, Unit.PCT);
}
- if (BrowserInfo.get().isIE()) {
+ if (BrowserInfo.get().isIE()
+ && BrowserInfo.get().getBrowserMajorVersion() < 11) {
+ // Must take margin,border,padding manually into account for
+ // menu element as we measure the element child and set width to
+ // the element parent
+ double naturalMenuOuterWidth = WidgetUtil
+ .getRequiredWidthDouble(menuFirstChild)
+ + getMarginBorderPaddingWidth(menu.getElement());
+
/*
* IE requires us to specify the width for the container
* element. Otherwise it will be 100% wide
*/
- int rootWidth = Math.max(desiredWidth, naturalMenuWidth)
- - popupOuterPadding;
+ double rootWidth = Math.max(desiredWidth - popupOuterPadding,
+ naturalMenuOuterWidth);
getContainerElement().getStyle().setWidth(rootWidth, Unit.PX);
}
@@ -1280,6 +1292,12 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
sinkEvents(Event.ONPASTE);
}
+ private static double getMarginBorderPaddingWidth(Element element) {
+ final ComputedStyle s = new ComputedStyle(element);
+ return s.getMarginWidth() + s.getBorderWidth() + s.getPaddingWidth();
+
+ }
+
/*
* (non-Javadoc)
*
@@ -2185,11 +2203,15 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
@Override
public com.google.gwt.user.client.Element getSubPartElement(String subPart) {
- if ("textbox".equals(subPart)) {
+ String[] parts = subPart.split("/");
+ if ("textbox".equals(parts[0])) {
return tb.getElement();
- } else if ("button".equals(subPart)) {
+ } else if ("button".equals(parts[0])) {
return popupOpener.getElement();
- } else if ("popup".equals(subPart) && suggestionPopup.isAttached()) {
+ } else if ("popup".equals(parts[0]) && suggestionPopup.isAttached()) {
+ if (parts.length == 2) {
+ return suggestionPopup.menu.getSubPartElement(parts[1]);
+ }
return suggestionPopup.getElement();
}
return null;
@@ -2233,4 +2255,10 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
selectPopupItemWhenResponseIsReceived = Select.NONE;
}
+ @Override
+ public boolean isWorkPending() {
+ return waitingForFilteringResponse
+ || suggestionPopup.lazyPageScroller.isRunning();
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java
index 84a9b4f3dd..bcbb3ebf7b 100644
--- a/client/src/com/vaadin/client/ui/VFormLayout.java
+++ b/client/src/com/vaadin/client/ui/VFormLayout.java
@@ -22,7 +22,6 @@ import java.util.List;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
@@ -327,22 +326,6 @@ public class VFormLayout extends SimplePanel {
requiredFieldIndicator = null;
}
}
-
- // Workaround for IE weirdness, sometimes returns bad height in some
- // circumstances when Caption is empty. See #1444
- // IE7 bugs more often. I wonder what happens when IE8 arrives...
- // FIXME: This could be unnecessary for IE8+
- if (BrowserInfo.get().isIE()) {
- if (isEmpty) {
- setHeight("0px");
- getElement().getStyle().setOverflow(Overflow.HIDDEN);
- } else {
- setHeight("");
- getElement().getStyle().clearOverflow();
- }
-
- }
-
}
/**
diff --git a/client/src/com/vaadin/client/ui/VRichTextArea.java b/client/src/com/vaadin/client/ui/VRichTextArea.java
index 3f63f38067..cb4482f7cb 100644
--- a/client/src/com/vaadin/client/ui/VRichTextArea.java
+++ b/client/src/com/vaadin/client/ui/VRichTextArea.java
@@ -322,7 +322,7 @@ public class VRichTextArea extends Composite implements Field, KeyPressHandler,
if ("<br>".equals(result)) {
result = "";
}
- } else if (browser.isWebkit()) {
+ } else if (browser.isWebkit() || browser.isEdge()) {
if ("<br>".equals(result) || "<div><br></div>".equals(result)) {
result = "";
}
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index 2724daae77..6bb8f063a6 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -1295,8 +1295,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (uidl.hasVariable("selected")) {
final Set<String> selectedKeys = uidl
.getStringArrayVariableAsSet("selected");
- removeUnselectedRowKeys(selectedKeys);
-
+ // Do not update focus if there is a single selected row
+ // that is the same as the previous selection. This prevents
+ // unwanted scrolling (#18247).
+ boolean rowsUnSelected = removeUnselectedRowKeys(selectedKeys);
+ boolean updateFocus = rowsUnSelected || selectedRowKeys.size() == 0
+ || focusedRow == null;
if (scrollBody != null) {
Iterator<Widget> iterator = scrollBody.iterator();
while (iterator.hasNext()) {
@@ -1313,7 +1317,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
selected = true;
keyboardSelectionOverRowFetchInProgress = true;
}
- if (selected && selectedKeys.size() == 1) {
+ if (selected && selectedKeys.size() == 1 && updateFocus) {
/*
* If a single item is selected, move focus to the
* selected row. (#10522)
@@ -1338,14 +1342,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return keyboardSelectionOverRowFetchInProgress;
}
- private void removeUnselectedRowKeys(final Set<String> selectedKeys) {
+ private boolean removeUnselectedRowKeys(final Set<String> selectedKeys) {
List<String> unselectedKeys = new ArrayList<String>(0);
for (String key : selectedRowKeys) {
if (!selectedKeys.contains(key)) {
unselectedKeys.add(key);
}
}
- selectedRowKeys.removeAll(unselectedKeys);
+ return selectedRowKeys.removeAll(unselectedKeys);
}
/** For internal use only. May be removed or replaced in the future. */
@@ -3629,6 +3633,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
} else {
c.setText(caption);
+ if (BrowserInfo.get().isIE10()) {
+ // IE10 can some times define min-height to include
+ // padding when setting the text...
+ // See https://dev.vaadin.com/ticket/15169
+ WidgetUtil.forceIERedraw(c.getElement());
+ }
}
c.setSorted(false);
diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java
index ded9977f5e..e196870348 100644
--- a/client/src/com/vaadin/client/ui/VTabsheet.java
+++ b/client/src/com/vaadin/client/ui/VTabsheet.java
@@ -61,11 +61,12 @@ import com.google.gwt.user.client.ui.impl.FocusImpl;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ComputedStyle;
import com.vaadin.client.Focusable;
import com.vaadin.client.TooltipInfo;
-import com.vaadin.client.WidgetUtil;
import com.vaadin.client.VCaption;
import com.vaadin.client.VTooltip;
+import com.vaadin.client.WidgetUtil;
import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.ComponentConstants;
@@ -1227,8 +1228,13 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware
public void updateContentNodeHeight() {
if (!isDynamicHeight()) {
int contentHeight = getOffsetHeight();
- contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight");
+ contentHeight -= deco.getOffsetHeight();
contentHeight -= tb.getOffsetHeight();
+
+ ComputedStyle cs = new ComputedStyle(contentNode);
+ contentHeight -= Math.ceil(cs.getPaddingHeight());
+ contentHeight -= Math.ceil(cs.getBorderHeight());
+
if (contentHeight < 0) {
contentHeight = 0;
}
diff --git a/client/src/com/vaadin/client/ui/VTextArea.java b/client/src/com/vaadin/client/ui/VTextArea.java
index 50930f2fee..bb3d3a476b 100644
--- a/client/src/com/vaadin/client/ui/VTextArea.java
+++ b/client/src/com/vaadin/client/ui/VTextArea.java
@@ -224,16 +224,16 @@ public class VTextArea extends VTextField implements DragImageModifier {
protected boolean browserSupportsMaxLengthAttribute() {
BrowserInfo info = BrowserInfo.get();
- if (info.isFirefox() && info.isBrowserVersionNewerOrEqual(4, 0)) {
+ if (info.isFirefox()) {
return true;
}
- if (info.isSafari() && info.isBrowserVersionNewerOrEqual(5, 0)) {
+ if (info.isSafari()) {
return true;
}
- if (info.isIE() && info.isBrowserVersionNewerOrEqual(10, 0)) {
+ if (info.isIE10() || info.isIE11() || info.isEdge()) {
return true;
}
- if (info.isAndroid() && info.isBrowserVersionNewerOrEqual(2, 3)) {
+ if (info.isAndroid()) {
return true;
}
return false;
diff --git a/client/src/com/vaadin/client/ui/VTree.java b/client/src/com/vaadin/client/ui/VTree.java
index 8729de4a43..846b16d0cb 100644
--- a/client/src/com/vaadin/client/ui/VTree.java
+++ b/client/src/com/vaadin/client/ui/VTree.java
@@ -179,7 +179,7 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
@Override
public void execute() {
- Util.notifyParentOfSizeChange(VTree.this, true);
+ doLayout();
}
});
@@ -969,7 +969,7 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
open = state;
if (!rendering) {
- Util.notifyParentOfSizeChange(VTree.this, false);
+ doLayout();
}
}
@@ -2239,4 +2239,15 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
com.google.gwt.user.client.Element captionElement) {
AriaHelper.bindCaption(body, captionElement);
}
+
+ /**
+ * Tell LayoutManager that a layout is needed later for this VTree
+ */
+ private void doLayout() {
+ // IE8 needs a hack to measure the tree again after update
+ WidgetUtil.forceIE8Redraw(getElement());
+
+ // This calls LayoutManager setNeedsMeasure and layoutNow
+ Util.notifyParentOfSizeChange(this, false);
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VUI.java b/client/src/com/vaadin/client/ui/VUI.java
index 0c1b83ab0f..963d83a6e6 100644
--- a/client/src/com/vaadin/client/ui/VUI.java
+++ b/client/src/com/vaadin/client/ui/VUI.java
@@ -18,7 +18,6 @@ package com.vaadin.client.ui;
import java.util.ArrayList;
-import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.HasScrollHandlers;
@@ -44,8 +43,8 @@ import com.vaadin.client.ConnectorMap;
import com.vaadin.client.Focusable;
import com.vaadin.client.LayoutManager;
import com.vaadin.client.Profiler;
-import com.vaadin.client.WidgetUtil;
import com.vaadin.client.VConsole;
+import com.vaadin.client.WidgetUtil;
import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.client.ui.ui.UIConnector;
@@ -515,13 +514,6 @@ public class VUI extends SimplePanel implements ResizeHandler,
public void focusStoredElement() {
if (storedFocus != null) {
storedFocus.focus();
-
- Scheduler.get().scheduleDeferred(new ScheduledCommand() {
- @Override
- public void execute() {
- storedFocus.focus();
- }
- });
}
}
diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java
index c5cab8ff6b..2d2d6ecee1 100644
--- a/client/src/com/vaadin/client/ui/VWindow.java
+++ b/client/src/com/vaadin/client/ui/VWindow.java
@@ -44,8 +44,6 @@ import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
-import com.google.gwt.event.dom.client.KeyUpEvent;
-import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.shared.HandlerRegistration;
@@ -79,8 +77,7 @@ import com.vaadin.shared.ui.window.WindowRole;
* @author Vaadin Ltd
*/
public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
- ScrollHandler, KeyDownHandler, KeyUpHandler, FocusHandler, BlurHandler,
- Focusable {
+ ScrollHandler, KeyDownHandler, FocusHandler, BlurHandler, Focusable {
private static ArrayList<VWindow> windowOrder = new ArrayList<VWindow>();
@@ -221,7 +218,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
constructDOM();
contentPanel.addScrollHandler(this);
contentPanel.addKeyDownHandler(this);
- contentPanel.addKeyUpHandler(this);
contentPanel.addFocusHandler(this);
contentPanel.addBlurHandler(this);
}
@@ -562,17 +558,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}
private static void focusTopmostModalWindow() {
- // If we call focus() directly without scheduling, it does not work in
- // IE and FF.
- Scheduler.get().scheduleDeferred(new ScheduledCommand() {
- @Override
- public void execute() {
- VWindow topmost = getTopmostWindow();
- if ((topmost != null) && (topmost.vaadinModality)) {
- topmost.focus();
- }
- }
- });
+ VWindow topmost = getTopmostWindow();
+ if ((topmost != null) && (topmost.vaadinModality)) {
+ topmost.focus();
+ }
}
@Override
@@ -762,11 +751,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
modalityCurtain.removeFromParent();
- if (BrowserInfo.get().isIE()) {
- // IE leaks memory in certain cases unless we release the reference
- // (#9197)
- modalityCurtain = null;
- }
+ // IE leaks memory in certain cases unless we release the reference
+ // (#9197)
+ modalityCurtain = null;
}
/*
@@ -1353,13 +1340,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}
@Override
- public void onKeyUp(KeyUpEvent event) {
- if (isClosable() && event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
- onCloseClick();
- }
- }
-
- @Override
public void onBlur(BlurEvent event) {
if (client.hasEventListeners(this, EventId.BLUR)) {
client.updateVariable(id, EventId.BLUR, "", true);
@@ -1375,7 +1355,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
@Override
public void focus() {
- contentPanel.focus();
+ // We don't want to use contentPanel.focus() as that will use a timer in
+ // Chrome/Safari and ultimately run focus events in the wrong order when
+ // opening a modal window and focusing some other component at the same
+ // time
+ contentPanel.getElement().focus();
}
private int getDecorationHeight() {
diff --git a/client/src/com/vaadin/client/ui/button/ButtonConnector.java b/client/src/com/vaadin/client/ui/button/ButtonConnector.java
index 2d13d62a91..2c2006e19b 100644
--- a/client/src/com/vaadin/client/ui/button/ButtonConnector.java
+++ b/client/src/com/vaadin/client/ui/button/ButtonConnector.java
@@ -16,24 +16,17 @@
package com.vaadin.client.ui.button;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
-import com.vaadin.client.EventHelper;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.VCaption;
import com.vaadin.client.annotations.OnStateChange;
-import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VButton;
import com.vaadin.shared.MouseEventDetails;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.shared.ui.button.ButtonServerRpc;
@@ -42,10 +35,7 @@ import com.vaadin.ui.Button;
@Connect(value = Button.class, loadStyle = LoadStyle.EAGER)
public class ButtonConnector extends AbstractComponentConnector implements
- BlurHandler, FocusHandler, ClickHandler {
-
- private HandlerRegistration focusHandlerRegistration = null;
- private HandlerRegistration blurHandlerRegistration = null;
+ ClickHandler {
@Override
public boolean delegateCaptionHandling() {
@@ -57,6 +47,7 @@ public class ButtonConnector extends AbstractComponentConnector implements
super.init();
getWidget().addClickHandler(this);
getWidget().client = getConnection();
+ ConnectorFocusAndBlurHandler.addHandlers(this);
}
@OnStateChange("errorMessage")
@@ -90,15 +81,6 @@ public class ButtonConnector extends AbstractComponentConnector implements
}
}
- @Override
- public void onStateChanged(StateChangeEvent stateChangeEvent) {
- super.onStateChanged(stateChangeEvent);
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration);
- }
-
@OnStateChange({ "caption", "captionAsHtml" })
void setCaption() {
VCaption.setCaptionText(getWidget().captionElement, getState());
@@ -127,20 +109,6 @@ public class ButtonConnector extends AbstractComponentConnector implements
}
@Override
- public void onFocus(FocusEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).focus();
- }
-
- @Override
- public void onBlur(BlurEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).blur();
- }
-
- @Override
public void onClick(ClickEvent event) {
if (getState().disableOnClick) {
// Simulate getting disabled from the server without waiting for the
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
index 1a54fe0454..55834397d3 100644
--- a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
@@ -268,8 +268,13 @@ public class DateCellDayEvent extends FocusableHTML implements
}
int endX = event.getClientX();
int endY = event.getClientY();
- int xDiff = startX - endX;
- int yDiff = startY - endY;
+ int xDiff = 0, yDiff = 0;
+ if (startX != -1 && startY != -1) {
+ // Drag started
+ xDiff = startX - endX;
+ yDiff = startY - endY;
+ }
+
startX = -1;
startY = -1;
mouseMoveStarted = false;
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 3bf6930933..158241337b 100644
--- a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java
@@ -392,8 +392,11 @@ public class SimpleDayCell extends FocusableFlowPanel implements
int endX = event.getClientX();
int endY = event.getClientY();
- int xDiff = startX - endX;
- int yDiff = startY - endY;
+ int xDiff = 0, yDiff = 0;
+ if (startX != -1 && startY != -1) {
+ xDiff = startX - endX;
+ yDiff = startY - endY;
+ }
startX = -1;
startY = -1;
prevDayDiff = 0;
diff --git a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
index 9e689f3314..8cfcf7feb1 100644
--- a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
+++ b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
@@ -16,25 +16,19 @@
package com.vaadin.client.ui.checkbox;
import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
-import com.vaadin.client.EventHelper;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.VCaption;
import com.vaadin.client.VTooltip;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractFieldConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VCheckBox;
import com.vaadin.shared.MouseEventDetails;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc;
import com.vaadin.shared.ui.checkbox.CheckBoxState;
@@ -42,10 +36,7 @@ import com.vaadin.ui.CheckBox;
@Connect(CheckBox.class)
public class CheckBoxConnector extends AbstractFieldConnector implements
- FocusHandler, BlurHandler, ClickHandler {
-
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
+ ClickHandler {
@Override
public boolean delegateCaptionHandling() {
@@ -55,21 +46,18 @@ public class CheckBoxConnector extends AbstractFieldConnector implements
@Override
protected void init() {
super.init();
+
getWidget().addClickHandler(this);
getWidget().client = getConnection();
getWidget().id = getConnectorId();
+ ConnectorFocusAndBlurHandler.addHandlers(this);
}
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration);
-
if (null != getState().errorMessage) {
getWidget().setAriaInvalid(true);
@@ -127,20 +115,6 @@ public class CheckBoxConnector extends AbstractFieldConnector implements
}
@Override
- public void onFocus(FocusEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).focus();
- }
-
- @Override
- public void onBlur(BlurEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).blur();
- }
-
- @Override
public void onClick(ClickEvent event) {
if (!isEnabled()) {
return;
diff --git a/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java b/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
index 2aae9beae6..65d4a1eb9b 100644
--- a/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
+++ b/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
@@ -15,30 +15,20 @@
*/
package com.vaadin.client.ui.nativebutton;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
-import com.vaadin.client.EventHelper;
import com.vaadin.client.VCaption;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VNativeButton;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.NativeButtonState;
import com.vaadin.ui.NativeButton;
@Connect(NativeButton.class)
-public class NativeButtonConnector extends AbstractComponentConnector implements
- BlurHandler, FocusHandler {
-
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
+public class NativeButtonConnector extends AbstractComponentConnector {
@Override
public void init() {
@@ -47,6 +37,8 @@ public class NativeButtonConnector extends AbstractComponentConnector implements
getWidget().buttonRpcProxy = getRpcProxy(ButtonServerRpc.class);
getWidget().client = getConnection();
getWidget().paintableId = getConnectorId();
+
+ ConnectorFocusAndBlurHandler.addHandlers(this);
}
@Override
@@ -59,10 +51,6 @@ public class NativeButtonConnector extends AbstractComponentConnector implements
super.onStateChanged(stateChangeEvent);
getWidget().disableOnClick = getState().disableOnClick;
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration);
// Set text
VCaption.setCaptionText(getWidget(), getState());
@@ -107,19 +95,4 @@ public class NativeButtonConnector extends AbstractComponentConnector implements
public NativeButtonState getState() {
return (NativeButtonState) super.getState();
}
-
- @Override
- public void onFocus(FocusEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).focus();
- }
-
- @Override
- public void onBlur(BlurEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).blur();
- }
-
}
diff --git a/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
index 938903da9a..d6ff2015b4 100644
--- a/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
+++ b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
@@ -16,55 +16,23 @@
package com.vaadin.client.ui.nativeselect;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.vaadin.client.EventHelper;
-import com.vaadin.client.annotations.OnStateChange;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.VNativeSelect;
import com.vaadin.client.ui.optiongroup.OptionGroupBaseConnector;
-import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.ui.NativeSelect;
@Connect(NativeSelect.class)
-public class NativeSelectConnector extends OptionGroupBaseConnector implements
- BlurHandler, FocusHandler {
+public class NativeSelectConnector extends OptionGroupBaseConnector {
- private HandlerRegistration focusHandlerRegistration = null;
- private HandlerRegistration blurHandlerRegistration = null;
-
- public NativeSelectConnector() {
- super();
- }
-
- @OnStateChange("registeredEventListeners")
- private void onServerEventListenerChanged() {
- focusHandlerRegistration = EventHelper.updateFocusHandler(this,
- focusHandlerRegistration, getWidget().getSelect());
- blurHandlerRegistration = EventHelper.updateBlurHandler(this,
- blurHandlerRegistration, getWidget().getSelect());
+ @Override
+ protected void init() {
+ super.init();
+ ConnectorFocusAndBlurHandler.addHandlers(this, getWidget().getSelect());
}
@Override
public VNativeSelect getWidget() {
return (VNativeSelect) super.getWidget();
}
-
- @Override
- public void onFocus(FocusEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).focus();
- }
-
- @Override
- public void onBlur(BlurEvent event) {
- // EventHelper.updateFocusHandler ensures that this is called only when
- // there is a listener on server side
- getRpcProxy(FocusAndBlurServerRpc.class).blur();
- }
-
}
diff --git a/client/src/com/vaadin/client/ui/tree/TreeConnector.java b/client/src/com/vaadin/client/ui/tree/TreeConnector.java
index fc3e6ca0fc..23091d0ad5 100644
--- a/client/src/com/vaadin/client/ui/tree/TreeConnector.java
+++ b/client/src/com/vaadin/client/ui/tree/TreeConnector.java
@@ -27,8 +27,8 @@ import com.vaadin.client.BrowserInfo;
import com.vaadin.client.Paintable;
import com.vaadin.client.TooltipInfo;
import com.vaadin.client.UIDL;
-import com.vaadin.client.WidgetUtil;
import com.vaadin.client.VConsole;
+import com.vaadin.client.WidgetUtil;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.VTree;
@@ -62,6 +62,10 @@ public class TreeConnector extends AbstractComponentConnector implements
if (uidl.hasAttribute("partialUpdate")) {
handleUpdate(uidl);
+
+ // IE8 needs a hack to measure the tree again after update
+ WidgetUtil.forceIE8Redraw(getWidget().getElement());
+
getWidget().rendering = false;
return;
}
diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java
index d67c953c6e..f5656dfdc4 100644
--- a/client/src/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java
@@ -59,6 +59,7 @@ import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadListener;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.UIDL;
+import com.vaadin.client.Util;
import com.vaadin.client.VConsole;
import com.vaadin.client.ValueMap;
import com.vaadin.client.annotations.OnStateChange;
@@ -71,6 +72,7 @@ import com.vaadin.client.ui.ShortcutActionHandler;
import com.vaadin.client.ui.VNotification;
import com.vaadin.client.ui.VOverlay;
import com.vaadin.client.ui.VUI;
+import com.vaadin.client.ui.VWindow;
import com.vaadin.client.ui.layout.MayScrollChildren;
import com.vaadin.client.ui.window.WindowConnector;
import com.vaadin.server.Page.Styles;
@@ -319,19 +321,19 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
- ComponentConnector paintable = (ComponentConnector) uidl
+ ComponentConnector connector = (ComponentConnector) uidl
.getPaintableAttribute("focused", getConnection());
- if (paintable == null) {
+ if (connector == null) {
// Do not try to focus invisible components which not
// present in UIDL
return;
}
- final Widget toBeFocused = paintable.getWidget();
+ final Widget toBeFocused = connector.getWidget();
/*
* Two types of Widgets can be focused, either implementing
- * GWT HasFocus of a thinner Vaadin specific Focusable
+ * GWT Focusable of a thinner Vaadin specific Focusable
* interface.
*/
if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
@@ -340,7 +342,14 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
} else if (toBeFocused instanceof Focusable) {
((Focusable) toBeFocused).focus();
} else {
- VConsole.log("Could not focus component");
+ getLogger()
+ .severe("Server is trying to set focus to the widget of connector "
+ + Util.getConnectorString(connector)
+ + " but it is not focusable. The widget should implement either "
+ + com.google.gwt.user.client.ui.Focusable.class
+ .getName()
+ + " or "
+ + Focusable.class.getName());
}
}
});
@@ -669,6 +678,19 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
if (c instanceof WindowConnector) {
WindowConnector wc = (WindowConnector) c;
wc.setWindowOrderAndPosition();
+ VWindow window = wc.getWidget();
+ if (!window.isAttached()) {
+
+ // Attach so that all widgets inside the Window are attached
+ // when their onStateChange is run
+
+ // Made invisible here for legacy reasons and made visible
+ // at the end of stateChange. This dance could probably be
+ // removed
+ window.setVisible(false);
+ window.show();
+ }
+
}
}
@@ -752,8 +774,7 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
getState().pushConfiguration.mode.isEnabled());
}
if (stateChangeEvent.hasPropertyChanged("reconnectDialogConfiguration")) {
- getConnection().getConnectionStateHandler()
- .configurationUpdated();
+ getConnection().getConnectionStateHandler().configurationUpdated();
}
if (stateChangeEvent.hasPropertyChanged("overlayContainerLabel")) {
@@ -1022,59 +1043,16 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
- forceStateChangeRecursively(UIConnector.this);
- // UIDL has no stored URL which we can repaint so we do some find and
- // replace magic...
- String newThemeBase = getConnection().translateVaadinUri("theme://");
- replaceThemeAttribute(oldThemeBase, newThemeBase);
+ // Request a full resynchronization from the server to deal with legacy
+ // components
+ getConnection().getMessageSender().resynchronize();
+ // Immediately update state and do layout while waiting for the resync
+ forceStateChangeRecursively(UIConnector.this);
getLayoutManager().forceLayout();
}
/**
- * Finds all attributes where theme:// urls have possibly been used and
- * replaces any old theme url with a new one
- *
- * @param oldPrefix
- * The start of the old theme URL
- * @param newPrefix
- * The start of the new theme URL
- */
- private void replaceThemeAttribute(String oldPrefix, String newPrefix) {
- // Images
- replaceThemeAttribute("src", oldPrefix, newPrefix);
- // Embedded flash
- replaceThemeAttribute("value", oldPrefix, newPrefix);
- replaceThemeAttribute("movie", oldPrefix, newPrefix);
- }
-
- /**
- * Finds any attribute of the given type where theme:// urls have possibly
- * been used and replaces any old theme url with a new one
- *
- * @param attributeName
- * The name of the attribute, e.g. "src"
- * @param oldPrefix
- * The start of the old theme URL
- * @param newPrefix
- * The start of the new theme URL
- */
- private void replaceThemeAttribute(String attributeName, String oldPrefix,
- String newPrefix) {
- // Find all "attributeName=" which start with "oldPrefix" using e.g.
- // [^src='http://oldpath']
- NodeList<Element> elements = querySelectorAll("[" + attributeName
- + "^='" + oldPrefix + "']");
- for (int i = 0; i < elements.getLength(); i++) {
- Element element = elements.getItem(i);
- element.setAttribute(
- attributeName,
- element.getAttribute(attributeName).replace(oldPrefix,
- newPrefix));
- }
- }
-
- /**
* Force a full recursive recheck of every connector's state variables.
*
* @see #forceStateChange()
diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java
index 9b710981d8..9ea3c8bb68 100644
--- a/client/src/com/vaadin/client/ui/window/WindowConnector.java
+++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java
@@ -17,6 +17,8 @@ package com.vaadin.client.ui.window;
import java.util.logging.Logger;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
@@ -354,10 +356,6 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
if (state.modal != window.vaadinModality) {
window.setVaadinModality(!window.vaadinModality);
}
- if (!window.isAttached()) {
- window.setVisible(false); // hide until possible centering
- window.show();
- }
boolean resizeable = state.resizable
&& state.windowMode == WindowMode.NORMAL;
window.setResizable(resizeable);
@@ -407,7 +405,13 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
window.centered = state.centered;
// Ensure centering before setting visible (#16486)
if (window.centered && getState().windowMode != WindowMode.MAXIMIZED) {
- window.center();
+ Scheduler.get().scheduleFinally(new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ getWidget().center();
+ }
+ });
}
window.setVisible(true);
diff --git a/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java b/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java
new file mode 100644
index 0000000000..564b0f1a03
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java
@@ -0,0 +1,225 @@
+/*
+ * 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.widget.grid;
+
+import com.google.gwt.core.client.Duration;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.Event;
+import com.vaadin.client.WidgetUtil;
+import com.vaadin.client.ui.FocusUtil;
+import com.vaadin.client.widget.grid.events.EditorMoveEvent;
+import com.vaadin.client.widget.grid.events.EditorOpenEvent;
+import com.vaadin.client.widgets.Grid.Editor;
+import com.vaadin.client.widgets.Grid.EditorDomEvent;
+
+/**
+ * The default handler for Grid editor events. Offers several overridable
+ * protected methods for easier customization.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> {
+
+ public static final int KEYCODE_OPEN = KeyCodes.KEY_ENTER;
+ public static final int KEYCODE_MOVE = KeyCodes.KEY_ENTER;
+ public static final int KEYCODE_CLOSE = KeyCodes.KEY_ESCAPE;
+
+ private double lastTouchEventTime = 0;
+ private int lastTouchEventX = -1;
+ private int lastTouchEventY = -1;
+ private int lastTouchEventRow = -1;
+
+ /**
+ * Returns whether the given event is a touch event that should open the
+ * editor.
+ *
+ * @param event
+ * the received event
+ * @return whether the event is a touch open event
+ */
+ protected boolean isTouchOpenEvent(EditorDomEvent<T> event) {
+ final Event e = event.getDomEvent();
+ final int type = e.getTypeInt();
+
+ final double now = Duration.currentTimeMillis();
+ final int currentX = WidgetUtil.getTouchOrMouseClientX(e);
+ final int currentY = WidgetUtil.getTouchOrMouseClientY(e);
+
+ final boolean validTouchOpenEvent = type == Event.ONTOUCHEND
+ && now - lastTouchEventTime < 500
+ && lastTouchEventRow == event.getCell().getRowIndex()
+ && Math.abs(lastTouchEventX - currentX) < 20
+ && Math.abs(lastTouchEventY - currentY) < 20;
+
+ if (type == Event.ONTOUCHSTART) {
+ lastTouchEventX = currentX;
+ lastTouchEventY = currentY;
+ }
+
+ if (type == Event.ONTOUCHEND) {
+ lastTouchEventTime = now;
+ lastTouchEventRow = event.getCell().getRowIndex();
+ }
+
+ return validTouchOpenEvent;
+ }
+
+ /**
+ * Returns whether the given event should open the editor. The default
+ * implementation returns true if and only if the event is a doubleclick or
+ * if it is a keydown event and the keycode is {@link #KEYCODE_OPEN}.
+ *
+ * @param event
+ * the received event
+ * @return true if the event is an open event, false otherwise
+ */
+ protected boolean isOpenEvent(EditorDomEvent<T> event) {
+ final Event e = event.getDomEvent();
+ return e.getTypeInt() == Event.ONDBLCLICK
+ || (e.getTypeInt() == Event.ONKEYDOWN && e.getKeyCode() == KEYCODE_OPEN)
+ || isTouchOpenEvent(event);
+ }
+
+ /**
+ * Opens the editor on the appropriate row if the received event is an open
+ * event. The default implementation uses
+ * {@link #isOpenEvent(EditorDomEvent) isOpenEvent}.
+ *
+ * @param event
+ * the received event
+ * @return true if this method handled the event and nothing else should be
+ * done, false otherwise
+ */
+ protected boolean handleOpenEvent(EditorDomEvent<T> event) {
+ if (isOpenEvent(event)) {
+ final EventCellReference<T> cell = event.getCell();
+
+ editRow(event, cell.getRowIndex(), cell.getColumnIndexDOM());
+
+ // FIXME should be in editRow
+ event.getGrid().fireEvent(new EditorOpenEvent(cell));
+
+ event.getDomEvent().preventDefault();
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Moves the editor to another row if the received event is a move event.
+ * The default implementation moves the editor to the clicked row if the
+ * event is a click; otherwise, if the event is a keydown and the keycode is
+ * {@link #KEYCODE_MOVE}, moves the editor one row up or down if the shift
+ * key is pressed or not, respectively.
+ *
+ * @param event
+ * the received event
+ * @return true if this method handled the event and nothing else should be
+ * done, false otherwise
+ */
+ protected boolean handleMoveEvent(EditorDomEvent<T> event) {
+ Event e = event.getDomEvent();
+ final EventCellReference<T> cell = event.getCell();
+
+ // TODO: Move on touch events
+ if (e.getTypeInt() == Event.ONCLICK) {
+
+ editRow(event, cell.getRowIndex(), cell.getColumnIndexDOM());
+
+ // FIXME should be in editRow
+ event.getGrid().fireEvent(new EditorMoveEvent(cell));
+
+ return true;
+ }
+
+ else if (e.getTypeInt() == Event.ONKEYDOWN
+ && e.getKeyCode() == KEYCODE_MOVE) {
+
+ editRow(event, event.getRowIndex() + (e.getShiftKey() ? -1 : +1),
+ event.getFocusedColumnIndex());
+
+ // FIXME should be in editRow
+ event.getGrid().fireEvent(new EditorMoveEvent(cell));
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns whether the given event should close the editor. The default
+ * implementation returns true if and only if the event is a keydown event
+ * and the keycode is {@link #KEYCODE_CLOSE}.
+ *
+ * @param event
+ * the received event
+ * @return true if the event is a close event, false otherwise
+ */
+ protected boolean isCloseEvent(EditorDomEvent<T> event) {
+ final Event e = event.getDomEvent();
+ return e.getTypeInt() == Event.ONKEYDOWN
+ && e.getKeyCode() == KEYCODE_CLOSE;
+ }
+
+ /**
+ * Closes the editor if the received event is a close event. The default
+ * implementation uses {@link #isCloseEvent(EditorDomEvent) isCloseEvent}.
+ *
+ * @param event
+ * the received event
+ * @return true if this method handled the event and nothing else should be
+ * done, false otherwise
+ */
+ protected boolean handleCloseEvent(EditorDomEvent<T> event) {
+ if (isCloseEvent(event)) {
+ event.getEditor().cancel();
+ FocusUtil.setFocus(event.getGrid(), true);
+ return true;
+ }
+ return false;
+ }
+
+ protected void editRow(EditorDomEvent<T> event, int rowIndex, int colIndex) {
+ int rowCount = event.getGrid().getDataSource().size();
+ // Limit rowIndex between 0 and rowCount - 1
+ rowIndex = Math.max(0, Math.min(rowCount - 1, rowIndex));
+
+ int colCount = event.getGrid().getVisibleColumns().size();
+ // Limit colIndex between 0 and colCount - 1
+ colIndex = Math.max(0, Math.min(colCount - 1, colIndex));
+
+ event.getEditor().editRow(rowIndex, colIndex);
+ }
+
+ @Override
+ public boolean handleEvent(EditorDomEvent<T> event) {
+ final Editor<T> editor = event.getEditor();
+ final boolean isBody = event.getCell().isBody();
+
+ if (event.getGrid().isEditorActive()) {
+ return (!editor.isBuffered() && isBody && handleMoveEvent(event))
+ || handleCloseEvent(event)
+ // Swallow events if editor is open and buffered (modal)
+ || editor.isBuffered();
+ } else {
+ return event.getGrid().isEnabled() && isBody
+ && handleOpenEvent(event);
+ }
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java
new file mode 100644
index 0000000000..99f59aa82a
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.widget.grid.events;
+
+import com.vaadin.client.widget.grid.CellReference;
+
+/**
+ * Event that gets fired when an open editor is closed (and not reopened
+ * elsewhere)
+ */
+public class EditorCloseEvent extends EditorEvent {
+
+ public EditorCloseEvent(CellReference<?> cell) {
+ super(cell);
+ }
+
+ @Override
+ protected void dispatch(EditorEventHandler handler) {
+ handler.onEditorClose(this);
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java
new file mode 100644
index 0000000000..eb34033197
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java
@@ -0,0 +1,108 @@
+/*
+ * 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.widget.grid.events;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.vaadin.client.widget.grid.CellReference;
+import com.vaadin.client.widgets.Grid;
+import com.vaadin.client.widgets.Grid.Column;
+
+/**
+ * Base class for editor events.
+ */
+public abstract class EditorEvent extends GwtEvent<EditorEventHandler> {
+ public static final Type<EditorEventHandler> TYPE = new Type<EditorEventHandler>();
+
+ private CellReference<?> cell;
+
+ protected EditorEvent(CellReference<?> cell) {
+ this.cell = cell;
+ }
+
+ @Override
+ public Type<EditorEventHandler> getAssociatedType() {
+ return TYPE;
+ }
+
+ /**
+ * Get a reference to the Grid that fired this Event.
+ *
+ * @return a Grid reference
+ */
+ @SuppressWarnings("unchecked")
+ public <T> Grid<T> getGrid() {
+ return (Grid<T>) cell.getGrid();
+ }
+
+ /**
+ * Get a reference to the cell that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return a cell reference
+ */
+ @SuppressWarnings("unchecked")
+ public <T> CellReference<T> getCell() {
+ return (CellReference<T>) cell;
+ }
+
+ /**
+ * Get a reference to the row that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return a row data object
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T getRow() {
+ return (T) cell.getRow();
+ }
+
+ /**
+ * Get the index of the row that was active when this Event was fired. NOTE:
+ * do <i>NOT</i> rely on this information remaining accurate after leaving
+ * the event handler.
+ *
+ * @return an integer value
+ */
+ public int getRowIndex() {
+ return cell.getRowIndex();
+ }
+
+ /**
+ * Get a reference to the column that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return a column object
+ */
+ @SuppressWarnings("unchecked")
+ public <C, T> Column<C, T> getColumn() {
+ return (Column<C, T>) cell.getColumn();
+ }
+
+ /**
+ * Get the index of the column that was active when this Event was fired.
+ * NOTE: do <i>NOT</i> rely on this information remaining accurate after
+ * leaving the event handler.
+ *
+ * @return an integer value
+ */
+ public int getColumnIndex() {
+ return cell.getColumnIndex();
+ }
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java b/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java
new file mode 100644
index 0000000000..4f9396a9f1
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java
@@ -0,0 +1,49 @@
+/*
+ * 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.widget.grid.events;
+
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Common handler interface for editor events
+ */
+public interface EditorEventHandler extends EventHandler {
+
+ /**
+ * Action to perform when the editor has been opened
+ *
+ * @param e
+ * an editor open event object
+ */
+ public void onEditorOpen(EditorOpenEvent e);
+
+ /**
+ * Action to perform when the editor is re-opened on another row
+ *
+ * @param e
+ * an editor move event object
+ */
+ public void onEditorMove(EditorMoveEvent e);
+
+ /**
+ * Action to perform when the editor is closed
+ *
+ * @param e
+ * an editor close event object
+ */
+ public void onEditorClose(EditorCloseEvent e);
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java
new file mode 100644
index 0000000000..0e5e2dcd7b
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.widget.grid.events;
+
+import com.vaadin.client.widget.grid.CellReference;
+
+/**
+ * Event that gets fired when an already open editor is closed and re-opened on
+ * another row
+ */
+public class EditorMoveEvent extends EditorEvent {
+
+ public EditorMoveEvent(CellReference<?> cell) {
+ super(cell);
+ }
+
+ @Override
+ protected void dispatch(EditorEventHandler handler) {
+ handler.onEditorMove(this);
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java
new file mode 100644
index 0000000000..df0171945f
--- /dev/null
+++ b/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.widget.grid.events;
+
+import com.vaadin.client.widget.grid.CellReference;
+
+/**
+ * Event that gets fired when the editor is opened
+ */
+public class EditorOpenEvent extends EditorEvent {
+
+ public EditorOpenEvent(CellReference<?> cell) {
+ super(cell);
+ }
+
+ @Override
+ protected void dispatch(EditorEventHandler handler) {
+ handler.onEditorOpen(this);
+ }
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
index 1e47d3ad6b..c64908f24c 100644
--- a/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
+++ b/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
@@ -56,6 +56,8 @@ import com.vaadin.client.widgets.Grid;
public class MultiSelectionRenderer<T> extends
ClickableRenderer<Boolean, CheckBox> {
+ private static final String SELECTION_CHECKBOX_CLASSNAME = "-selection-checkbox";
+
/** The size of the autoscroll area, both top and bottom. */
private static final int SCROLL_AREA_GRADIENT_PX = 100;
@@ -591,6 +593,8 @@ public class MultiSelectionRenderer<T> extends
@Override
public CheckBox createWidget() {
final CheckBox checkBox = GWT.create(CheckBox.class);
+ checkBox.setStylePrimaryName(grid.getStylePrimaryName()
+ + SELECTION_CHECKBOX_CLASSNAME);
CheckBoxEventHandler handler = new CheckBoxEventHandler(checkBox);
// Sink events
diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java
index 436b512294..43eeb7a0ce 100644
--- a/client/src/com/vaadin/client/widgets/Escalator.java
+++ b/client/src/com/vaadin/client/widgets/Escalator.java
@@ -29,11 +29,13 @@ import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
+import com.google.gwt.animation.client.Animation;
import com.google.gwt.animation.client.AnimationScheduler;
import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
import com.google.gwt.animation.client.AnimationScheduler.AnimationHandle;
import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.DivElement;
@@ -48,6 +50,7 @@ import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
+import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.logging.client.LogConfiguration;
import com.google.gwt.user.client.Command;
@@ -72,6 +75,7 @@ import com.vaadin.client.widget.escalator.PositionFunction.AbsolutePosition;
import com.vaadin.client.widget.escalator.PositionFunction.Translate3DPosition;
import com.vaadin.client.widget.escalator.PositionFunction.TranslatePosition;
import com.vaadin.client.widget.escalator.PositionFunction.WebkitTranslate3DPosition;
+import com.vaadin.client.widget.escalator.Row;
import com.vaadin.client.widget.escalator.RowContainer;
import com.vaadin.client.widget.escalator.RowContainer.BodyRowContainer;
import com.vaadin.client.widget.escalator.RowVisibilityChangeEvent;
@@ -302,8 +306,6 @@ public class Escalator extends Widget implements RequiresResize,
static class JsniUtil {
public static class TouchHandlerBundle {
- private static final double FLICK_POLL_FREQUENCY = 100d;
-
/**
* A <a href=
* "http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsOverlay.html"
@@ -338,105 +340,8 @@ public class Escalator extends Widget implements RequiresResize,
}-*/;
}
- private double touches = 0;
- private int lastX = 0;
- private int lastY = 0;
- private boolean snappedScrollEnabled = true;
- private double deltaX = 0;
- private double deltaY = 0;
-
private final Escalator escalator;
- private CustomTouchEvent latestTouchMoveEvent;
-
- /** The timestamp of {@link #flickPageX1} and {@link #flickPageY1} */
- private double flickStartTime = 0;
-
- /** The timestamp of {@link #flickPageX2} and {@link #flickPageY2} */
- private double flickTimestamp = 0;
-
- /** The most recent flick touch reference Y */
- private double flickPageY1 = -1;
- /** The most recent flick touch reference X */
- private double flickPageX1 = -1;
-
- /** The previous flick touch reference Y, before {@link #flickPageY1} */
- private double flickPageY2 = -1;
- /** The previous flick touch reference X, before {@link #flickPageX1} */
- private double flickPageX2 = -1;
-
- /**
- * This animation callback guarantees the fact that we don't scroll
- * the grid more than once per visible frame.
- *
- * It seems that there will never be more touch events than there
- * are rendered frames, but there's no guarantee for that. If it was
- * guaranteed, we probably could do all of this immediately in
- * {@link #touchMove(CustomTouchEvent)}, instead of deferring it
- * over here.
- */
- private AnimationCallback mover = new AnimationCallback() {
-
- @Override
- public void execute(double timestamp) {
- if (touches != 1) {
- return;
- }
-
- final int x = latestTouchMoveEvent.getPageX();
- final int y = latestTouchMoveEvent.getPageY();
-
- /*
- * Check if we need a new flick coordinate sample ( more
- * than FLICK_POLL_FREQUENCY ms have passed since the last
- * sample )
- */
- if (System.currentTimeMillis() - flickTimestamp > FLICK_POLL_FREQUENCY) {
-
- flickTimestamp = System.currentTimeMillis();
- // Set target coordinates
- flickPageY2 = y;
- flickPageX2 = x;
- }
-
- deltaX = x - lastX;
- deltaY = y - lastY;
- lastX = x;
- lastY = y;
-
- // snap the scroll to the major axes, at first.
- if (snappedScrollEnabled) {
- final double oldDeltaX = deltaX;
- final double oldDeltaY = deltaY;
-
- /*
- * Scrolling snaps to 40 degrees vs. flick scroll's 30
- * degrees, since slow movements have poor resolution -
- * it's easy to interpret a slight angle as a steep
- * angle, since the sample rate is "unnecessarily" high.
- * 40 simply felt better than 30.
- */
- final double[] snapped = Escalator.snapDeltas(deltaX,
- deltaY, RATIO_OF_40_DEGREES);
- deltaX = snapped[0];
- deltaY = snapped[1];
-
- /*
- * if the snap failed once, let's follow the pointer
- * from now on.
- */
- if (oldDeltaX != 0 && deltaX == oldDeltaX
- && oldDeltaY != 0 && deltaY == oldDeltaY) {
- snappedScrollEnabled = false;
- }
- }
-
- moveScrollFromEvent(escalator, -deltaX, -deltaY,
- latestTouchMoveEvent.getNativeEvent());
- }
- };
- private AnimationHandle animationHandle;
-
public TouchHandlerBundle(final Escalator escalator) {
this.escalator = escalator;
}
@@ -468,79 +373,157 @@ public class Escalator extends Widget implements RequiresResize,
});
}-*/;
- public void touchStart(final CustomTouchEvent event) {
- touches = event.getNativeEvent().getTouches().length();
- if (touches != 1) {
- return;
+ // Duration of the inertial scrolling simulation. Devices with
+ // larger screens take longer durations.
+ private static final int DURATION = (int)Window.getClientHeight();
+ // multiply scroll velocity with repeated touching
+ private int acceleration = 1;
+ private boolean touching = false;
+ // Two movement objects for storing status and processing touches
+ private Movement yMov, xMov;
+ final double MIN_VEL = 0.6, MAX_VEL = 4, F_VEL = 1500, F_ACC = 0.7, F_AXIS = 1;
+
+ // The object to deal with one direction scrolling
+ private class Movement {
+ final List<Double> speeds = new ArrayList<Double>();
+ final ScrollbarBundle scroll;
+ double position, offset, velocity, prevPos, prevTime, delta;
+ boolean run, vertical;
+
+ public Movement(boolean vertical) {
+ this.vertical = vertical;
+ scroll = vertical ? escalator.verticalScrollbar : escalator.horizontalScrollbar;
}
- escalator.scroller.cancelFlickScroll();
+ public void startTouch(CustomTouchEvent event) {
+ speeds.clear();
+ prevPos = pagePosition(event);
+ prevTime = Duration.currentTimeMillis();
+ }
+ public void moveTouch(CustomTouchEvent event) {
+ double pagePosition = pagePosition(event);
+ if (pagePosition > -1) {
+ delta = prevPos - pagePosition;
+ double now = Duration.currentTimeMillis();
+ double ellapsed = now - prevTime;
+ velocity = delta / ellapsed;
+ // if last speed was so low, reset speeds and start storing again
+ if (speeds.size() > 0 && !validSpeed(speeds.get(0))) {
+ speeds.clear();
+ run = true;
+ }
+ speeds.add(0, velocity);
+ prevTime = now;
+ prevPos = pagePosition;
+ }
+ }
+ public void endTouch(CustomTouchEvent event) {
+ // Compute average speed
+ velocity = 0;
+ for (double s : speeds) {
+ velocity += s / speeds.size();
+ }
+ position = scroll.getScrollPos();
+ // Compute offset, and adjust it with an easing curve so as movement is smoother.
+ offset = F_VEL * velocity * acceleration * easingInOutCos(velocity, MAX_VEL);
+ // Check that offset does not over-scroll
+ double minOff = -scroll.getScrollPos();
+ double maxOff = scroll.getScrollSize() - scroll.getOffsetSize() + minOff;
+ offset = Math.min(Math.max(offset, minOff), maxOff);
+ // Enable or disable inertia movement in this axis
+ run = validSpeed(velocity) && minOff < 0 && maxOff > 0;
+ if (run) {
+ event.getNativeEvent().preventDefault();
+ }
+ }
+ void validate(Movement other) {
+ if (!run || other.velocity > 0 && Math.abs(velocity / other.velocity) < F_AXIS) {
+ delta = offset = 0;
+ run = false;
+ }
+ }
+ void stepAnimation(double progress) {
+ scroll.setScrollPos(position + offset * progress);
+ }
- lastX = event.getPageX();
- lastY = event.getPageY();
+ int pagePosition(CustomTouchEvent event) {
+ JsArray<Touch> a = event.getNativeEvent().getTouches();
+ return vertical ? a.get(0).getPageY() : a.get(0).getPageX();
+ }
+ boolean validSpeed(double speed) {
+ return Math.abs(speed) > MIN_VEL;
+ }
+ }
- // Reset flick parameters
- flickPageX1 = lastX;
- flickPageX2 = -1;
- flickPageY1 = lastY;
- flickPageY2 = -1;
- flickStartTime = System.currentTimeMillis();
- flickTimestamp = 0;
+ // Using GWT animations which take care of native animation frames.
+ private Animation animation = new Animation() {
+ public void onUpdate(double progress) {
+ xMov.stepAnimation(progress);
+ yMov.stepAnimation(progress);
+ }
+ public double interpolate(double progress) {
+ return easingOutCirc(progress);
+ };
+ public void onComplete() {
+ touching = false;
+ escalator.body.domSorter.reschedule();
+ };
+ public void run(int duration) {
+ if (xMov.run || yMov.run) {
+ super.run(duration);
+ } else {
+ onComplete();
+ }
+ };
+ };
- snappedScrollEnabled = true;
+ public void touchStart(final CustomTouchEvent event) {
+ if (event.getNativeEvent().getTouches().length() == 1) {
+ if (yMov == null) {
+ yMov = new Movement(true);
+ xMov = new Movement(false);
+ }
+ if (animation.isRunning()) {
+ acceleration += F_ACC;
+ event.getNativeEvent().preventDefault();
+ animation.cancel();
+ } else {
+ acceleration = 1;
+ }
+ xMov.startTouch(event);
+ yMov.startTouch(event);
+ touching = true;
+ }
}
public void touchMove(final CustomTouchEvent event) {
- /*
- * since we only use the getPageX/Y, and calculate the diff
- * within the handler, we don't need to calculate any
- * intermediate deltas.
- */
- latestTouchMoveEvent = event;
-
- if (animationHandle != null) {
- animationHandle.cancel();
- }
- animationHandle = AnimationScheduler.get()
- .requestAnimationFrame(mover, escalator.bodyElem);
- event.getNativeEvent().preventDefault();
+ xMov.moveTouch(event);
+ yMov.moveTouch(event);
+ xMov.validate(yMov);
+ yMov.validate(xMov);
+ moveScrollFromEvent(escalator, xMov.delta, yMov.delta, event.getNativeEvent());
}
public void touchEnd(final CustomTouchEvent event) {
- touches = event.getNativeEvent().getTouches().length();
-
- if (touches == 0) {
-
- /*
- * We want to smooth the flick calculations here. We have
- * taken a frame of reference every FLICK_POLL_FREQUENCY.
- * But if the sample is too fresh, we might introduce noise
- * in our sampling, so we use the older sample instead. it
- * might be less accurate, but it's smoother.
- *
- * flickPage?1 is the most recent one, while flickPage?2 is
- * the previous one.
- */
-
- final double finalPageY;
- final double finalPageX;
- double deltaT = flickTimestamp - flickStartTime;
- boolean onlyOneSample = flickPageX2 < 0 || flickPageY2 < 0;
- if (onlyOneSample) {
- finalPageX = latestTouchMoveEvent.getPageX();
- finalPageY = latestTouchMoveEvent.getPageY();
- } else {
- finalPageY = flickPageY2;
- finalPageX = flickPageX2;
- }
-
- double deltaX = finalPageX - flickPageX1;
- double deltaY = finalPageY - flickPageY1;
+ xMov.endTouch(event);
+ yMov.endTouch(event);
+ xMov.validate(yMov);
+ yMov.validate(xMov);
+ // Adjust duration so as longer movements take more duration
+ boolean vert = !xMov.run || yMov.run && Math.abs(yMov.offset) > Math.abs(xMov.offset);
+ double delta = Math.abs((vert ? yMov : xMov).offset);
+ animation.run((int)(3 * DURATION * easingOutExp(delta)));
+ }
- escalator.scroller
- .handleFlickScroll(deltaX, deltaY, deltaT);
- escalator.body.domSorter.reschedule();
- }
+ private double easingInOutCos(double val, double max) {
+ return 0.5 - 0.5 * Math.cos(Math.PI * Math.signum(val)
+ * Math.min(Math.abs(val), max) / max);
+ }
+ private double easingOutExp(double delta) {
+ return (1 - Math.pow(2, -delta / 1000));
+ }
+ private double easingOutCirc(double progress) {
+ return Math.sqrt(1 - (progress - 1) * (progress - 1));
}
}
@@ -570,117 +553,6 @@ public class Escalator extends Widget implements RequiresResize,
}
}
- /**
- * The animation callback that handles the animation of a touch-scrolling
- * flick with inertia.
- */
- private class FlickScrollAnimator implements AnimationCallback {
- private static final double MIN_MAGNITUDE = 0.005;
- private static final double MAX_SPEED = 7;
-
- private double velX;
- private double velY;
- private double prevTime = 0;
- private int millisLeft;
- private double xFric;
- private double yFric;
-
- private boolean cancelled = false;
- private double lastLeft;
- private double lastTop;
-
- /**
- * Creates a new animation callback to handle touch-scrolling flick with
- * inertia.
- *
- * @param deltaX
- * the last scrolling delta in the x-axis in a touchmove
- * @param deltaY
- * the last scrolling delta in the y-axis in a touchmove
- * @param lastTime
- * the timestamp of the last touchmove
- */
- public FlickScrollAnimator(final double deltaX, final double deltaY,
- final double deltaT) {
- velX = Math.max(Math.min(deltaX / deltaT, MAX_SPEED), -MAX_SPEED);
- velY = Math.max(Math.min(deltaY / deltaT, MAX_SPEED), -MAX_SPEED);
-
- lastLeft = horizontalScrollbar.getScrollPos();
- lastTop = verticalScrollbar.getScrollPos();
-
- /*
- * If we're scrolling mainly in one of the four major directions,
- * and only a teeny bit to any other side, snap the scroll to that
- * major direction instead.
- */
- final double[] snapDeltas = Escalator.snapDeltas(velX, velY,
- RATIO_OF_30_DEGREES);
- velX = snapDeltas[0];
- velY = snapDeltas[1];
-
- if (velX * velX + velY * velY > MIN_MAGNITUDE) {
- millisLeft = 1500;
- xFric = velX / millisLeft;
- yFric = velY / millisLeft;
- } else {
- millisLeft = 0;
- }
-
- }
-
- @Override
- public void execute(final double doNotUseThisTimestamp) {
- /*
- * We cannot use the timestamp provided to this method since it is
- * of a format that cannot be determined at will. Therefore, we need
- * a timestamp format that we can handle, so our calculations are
- * correct.
- */
-
- if (millisLeft <= 0 || cancelled) {
- scroller.currentFlickScroller = null;
- return;
- }
-
- final double timestamp = Duration.currentTimeMillis();
- if (prevTime == 0) {
- prevTime = timestamp;
- AnimationScheduler.get().requestAnimationFrame(this);
- return;
- }
-
- double currentLeft = horizontalScrollbar.getScrollPos();
- double currentTop = verticalScrollbar.getScrollPos();
-
- final double timeDiff = timestamp - prevTime;
- double left = currentLeft - velX * timeDiff;
- setScrollLeft(left);
- velX -= xFric * timeDiff;
-
- double top = currentTop - velY * timeDiff;
- setScrollTop(top);
- velY -= yFric * timeDiff;
-
- cancelBecauseOfEdgeOrCornerMaybe();
-
- prevTime = timestamp;
- millisLeft -= timeDiff;
- lastLeft = currentLeft;
- lastTop = currentTop;
- AnimationScheduler.get().requestAnimationFrame(this);
- }
-
- private void cancelBecauseOfEdgeOrCornerMaybe() {
- if (lastLeft == horizontalScrollbar.getScrollPos()
- && lastTop == verticalScrollbar.getScrollPos()) {
- cancel();
- }
- }
-
- public void cancel() {
- cancelled = true;
- }
- }
/**
* ScrollDestination case-specific handling logic.
@@ -760,11 +632,6 @@ public class Escalator extends Widget implements RequiresResize,
private class Scroller extends JsniWorkaround {
private double lastScrollTop = 0;
private double lastScrollLeft = 0;
- /**
- * The current flick scroll animator. This is <code>null</code> if the
- * view isn't animating a flick scroll at the moment.
- */
- private FlickScrollAnimator currentFlickScroller;
public Scroller() {
super(Escalator.this);
@@ -782,7 +649,7 @@ public class Escalator extends Widget implements RequiresResize,
return $entry(function(e) {
var target = e.target || e.srcElement; // IE8 uses e.scrElement
-
+
// in case the scroll event was native (i.e. scrollbars were dragged, or
// the scrollTop/Left was manually modified), the bundles have old cache
// values. We need to make sure that the caches are kept up to date.
@@ -1100,30 +967,6 @@ public class Escalator extends Widget implements RequiresResize,
}
}-*/;
- private void cancelFlickScroll() {
- if (currentFlickScroller != null) {
- currentFlickScroller.cancel();
- }
- }
-
- /**
- * Handles a touch-based flick scroll.
- *
- * @param deltaX
- * the last scrolling delta in the x-axis in a touchmove
- * @param deltaY
- * the last scrolling delta in the y-axis in a touchmove
- * @param lastTime
- * the timestamp of the last touchmove
- */
- public void handleFlickScroll(double deltaX, double deltaY,
- double deltaT) {
- currentFlickScroller = new FlickScrollAnimator(deltaX, deltaY,
- deltaT);
- AnimationScheduler.get()
- .requestAnimationFrame(currentFlickScroller);
- }
-
public void scrollToColumn(final int columnIndex,
final ScrollDestination destination, final int padding) {
assert columnIndex >= columnConfiguration.frozenColumns : "Can't scroll to a frozen column";
@@ -1475,6 +1318,9 @@ public class Escalator extends Widget implements RequiresResize,
cellElem.addClassName("frozen");
position.set(cellElem, scroller.lastScrollLeft, 0);
}
+ if (columnConfiguration.frozenColumns > 0 && col == columnConfiguration.frozenColumns - 1) {
+ cellElem.addClassName("last-frozen");
+ }
}
referenceRow = paintInsertRow(referenceRow, tr, row);
@@ -1732,6 +1578,14 @@ public class Escalator extends Widget implements RequiresResize,
}
public void setColumnFrozen(int column, boolean frozen) {
+ toggleFrozenColumnClass(column, frozen, "frozen");
+
+ if (frozen) {
+ updateFreezePosition(column, scroller.lastScrollLeft);
+ }
+ }
+
+ private void toggleFrozenColumnClass(int column, boolean frozen, String className) {
final NodeList<TableRowElement> childRows = root.getRows();
for (int row = 0; row < childRows.getLength(); row++) {
@@ -1742,16 +1596,16 @@ public class Escalator extends Widget implements RequiresResize,
TableCellElement cell = tr.getCells().getItem(column);
if (frozen) {
- cell.addClassName("frozen");
+ cell.addClassName(className);
} else {
- cell.removeClassName("frozen");
+ cell.removeClassName(className);
position.reset(cell);
}
}
+ }
- if (frozen) {
- updateFreezePosition(column, scroller.lastScrollLeft);
- }
+ public void setColumnLastFrozen(int column, boolean lastFrozen) {
+ toggleFrozenColumnClass(column, lastFrozen, "last-frozen");
}
public void updateFreezePosition(int column, double scrollLeft) {
@@ -2470,9 +2324,9 @@ public class Escalator extends Widget implements RequiresResize,
private boolean sortIfConditionsMet() {
boolean enoughFramesHavePassed = framesPassed >= REQUIRED_FRAMES_PASSED;
boolean enoughTimeHasPassed = (Duration.currentTimeMillis() - startTime) >= SORT_DELAY_MILLIS;
- boolean notAnimatingFlick = (scroller.currentFlickScroller == null);
+ boolean notTouchActivity = !scroller.touchHandlerBundle.touching;
boolean conditionsMet = enoughFramesHavePassed
- && enoughTimeHasPassed && notAnimatingFlick;
+ && enoughTimeHasPassed && notTouchActivity;
if (conditionsMet) {
resetConditions();
@@ -2652,15 +2506,7 @@ public class Escalator extends Widget implements RequiresResize,
if (rowsWereMoved) {
fireRowVisibilityChangeEvent();
-
- if (scroller.touchHandlerBundle.touches == 0) {
- /*
- * this will never be called on touch scrolling. That is
- * handled separately and explicitly by
- * TouchHandlerBundle.touchEnd();
- */
- domSorter.reschedule();
- }
+ domSorter.reschedule();
}
}
@@ -2756,17 +2602,33 @@ public class Escalator extends Widget implements RequiresResize,
// move the surrounding rows to their correct places.
double rowTop = (unupdatedLogicalStart + (end - start))
* getDefaultRowHeight();
- final ListIterator<TableRowElement> i = visualRowOrder
- .listIterator(visualTargetIndex + (end - start));
-
- int logicalRowIndexCursor = unupdatedLogicalStart;
- while (i.hasNext()) {
- rowTop += spacerContainer
- .getSpacerHeight(logicalRowIndexCursor++);
- final TableRowElement tr = i.next();
- setRowPosition(tr, 0, rowTop);
- rowTop += getDefaultRowHeight();
+ // TODO: Get rid of this try/catch block by fixing the
+ // underlying issue. The reason for this erroneous behavior
+ // might be that Escalator actually works 'by mistake', and
+ // the order of operations is, in fact, wrong.
+ try {
+ final ListIterator<TableRowElement> i = visualRowOrder
+ .listIterator(visualTargetIndex + (end - start));
+
+ int logicalRowIndexCursor = unupdatedLogicalStart;
+ while (i.hasNext()) {
+ rowTop += spacerContainer
+ .getSpacerHeight(logicalRowIndexCursor++);
+
+ final TableRowElement tr = i.next();
+ setRowPosition(tr, 0, rowTop);
+ rowTop += getDefaultRowHeight();
+ }
+ } catch (Exception e) {
+ Logger logger = getLogger();
+ logger.warning("Ignored out-of-bounds row element access");
+ logger.warning("Escalator state: start=" + start
+ + ", end=" + end + ", visualTargetIndex="
+ + visualTargetIndex
+ + ", visualRowOrder.size()="
+ + visualRowOrder.size());
+ logger.warning(e.toString());
}
}
@@ -4309,6 +4171,17 @@ public class Escalator extends Widget implements RequiresResize,
firstUnaffectedCol = oldCount;
}
+ if (oldCount > 0) {
+ header.setColumnLastFrozen(oldCount - 1, false);
+ body.setColumnLastFrozen(oldCount - 1, false);
+ footer.setColumnLastFrozen(oldCount - 1, false);
+ }
+ if (count > 0) {
+ header.setColumnLastFrozen(count - 1, true);
+ body.setColumnLastFrozen(count - 1, true);
+ footer.setColumnLastFrozen(count - 1, true);
+ }
+
for (int col = firstAffectedCol; col < firstUnaffectedCol; col++) {
header.setColumnFrozen(col, frozen);
body.setColumnFrozen(col, frozen);
@@ -5619,14 +5492,29 @@ public class Escalator extends Widget implements RequiresResize,
horizontalScrollbar.setScrollbarThickness(scrollbarThickness);
horizontalScrollbar
.addVisibilityHandler(new ScrollbarBundle.VisibilityHandler() {
+
+ private boolean queued = false;
+
@Override
public void visibilityChanged(
ScrollbarBundle.VisibilityChangeEvent event) {
+ if (queued) {
+ return;
+ }
+ queued = true;
+
/*
* We either lost or gained a scrollbar. In any case, we
* need to change the height, if it's defined by rows.
*/
- applyHeightByRows();
+ Scheduler.get().scheduleFinally(new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ applyHeightByRows();
+ queued = false;
+ }
+ });
}
});
@@ -6022,10 +5910,14 @@ public class Escalator extends Widget implements RequiresResize,
public void scrollToRow(final int rowIndex,
final ScrollDestination destination, final int padding)
throws IndexOutOfBoundsException, IllegalArgumentException {
- validateScrollDestination(destination, padding);
- verifyValidRowIndex(rowIndex);
-
- scroller.scrollToRow(rowIndex, destination, padding);
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ validateScrollDestination(destination, padding);
+ verifyValidRowIndex(rowIndex);
+ scroller.scrollToRow(rowIndex, destination, padding);
+ }
+ });
}
private void verifyValidRowIndex(final int rowIndex) {
@@ -6086,55 +5978,62 @@ public class Escalator extends Widget implements RequiresResize,
* {@code destination == null}; or if {@code rowIndex == -1} and
* there is no spacer open at that index.
*/
- public void scrollToRowAndSpacer(int rowIndex,
- ScrollDestination destination, int padding)
+ public void scrollToRowAndSpacer(final int rowIndex,
+ final ScrollDestination destination, final int padding)
throws IllegalArgumentException {
- validateScrollDestination(destination, padding);
- if (rowIndex != -1) {
- verifyValidRowIndex(rowIndex);
- }
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ validateScrollDestination(destination, padding);
+ if (rowIndex != -1) {
+ verifyValidRowIndex(rowIndex);
+ }
- // row range
- final Range rowRange;
- if (rowIndex != -1) {
- int rowTop = (int) Math.floor(body.getRowTop(rowIndex));
- int rowHeight = (int) Math.ceil(body.getDefaultRowHeight());
- rowRange = Range.withLength(rowTop, rowHeight);
- } else {
- rowRange = Range.withLength(0, 0);
- }
+ // row range
+ final Range rowRange;
+ if (rowIndex != -1) {
+ int rowTop = (int) Math.floor(body.getRowTop(rowIndex));
+ int rowHeight = (int) Math.ceil(body.getDefaultRowHeight());
+ rowRange = Range.withLength(rowTop, rowHeight);
+ } else {
+ rowRange = Range.withLength(0, 0);
+ }
- // get spacer
- final SpacerContainer.SpacerImpl spacer = body.spacerContainer
- .getSpacer(rowIndex);
+ // get spacer
+ final SpacerContainer.SpacerImpl spacer = body.spacerContainer
+ .getSpacer(rowIndex);
- if (rowIndex == -1 && spacer == null) {
- throw new IllegalArgumentException("Cannot scroll to row index "
- + "-1, as there is no spacer open at that index.");
- }
+ if (rowIndex == -1 && spacer == null) {
+ throw new IllegalArgumentException(
+ "Cannot scroll to row index "
+ + "-1, as there is no spacer open at that index.");
+ }
- // make into target range
- final Range targetRange;
- if (spacer != null) {
- final int spacerTop = (int) Math.floor(spacer.getTop());
- final int spacerHeight = (int) Math.ceil(spacer.getHeight());
- Range spacerRange = Range.withLength(spacerTop, spacerHeight);
+ // make into target range
+ final Range targetRange;
+ if (spacer != null) {
+ final int spacerTop = (int) Math.floor(spacer.getTop());
+ final int spacerHeight = (int) Math.ceil(spacer.getHeight());
+ Range spacerRange = Range.withLength(spacerTop,
+ spacerHeight);
- targetRange = rowRange.combineWith(spacerRange);
- } else {
- targetRange = rowRange;
- }
+ targetRange = rowRange.combineWith(spacerRange);
+ } else {
+ targetRange = rowRange;
+ }
- // get params
- int targetStart = targetRange.getStart();
- int targetEnd = targetRange.getEnd();
- double viewportStart = getScrollTop();
- double viewportEnd = viewportStart + body.getHeightOfSection();
+ // get params
+ int targetStart = targetRange.getStart();
+ int targetEnd = targetRange.getEnd();
+ double viewportStart = getScrollTop();
+ double viewportEnd = viewportStart + body.getHeightOfSection();
- double scrollPos = getScrollPos(destination, targetStart, targetEnd,
- viewportStart, viewportEnd, padding);
+ double scrollPos = getScrollPos(destination, targetStart,
+ targetEnd, viewportStart, viewportEnd, padding);
- setScrollTop(scrollPos);
+ setScrollTop(scrollPos);
+ }
+ });
}
private static void validateScrollDestination(
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index 58fc532a77..fc8151272d 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -31,7 +31,6 @@ import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
-import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.core.shared.GWT;
@@ -42,6 +41,7 @@ import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
@@ -49,6 +49,9 @@ import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
@@ -79,6 +82,7 @@ import com.vaadin.client.Focusable;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
+import com.vaadin.client.data.DataSource.RowHandle;
import com.vaadin.client.renderers.ComplexRenderer;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.renderers.WidgetRenderer;
@@ -103,6 +107,7 @@ import com.vaadin.client.widget.grid.CellReference;
import com.vaadin.client.widget.grid.CellStyleGenerator;
import com.vaadin.client.widget.grid.DataAvailableEvent;
import com.vaadin.client.widget.grid.DataAvailableHandler;
+import com.vaadin.client.widget.grid.DefaultEditorEventHandler;
import com.vaadin.client.widget.grid.DetailsGenerator;
import com.vaadin.client.widget.grid.EditorHandler;
import com.vaadin.client.widget.grid.EditorHandler.EditorRequest;
@@ -121,6 +126,9 @@ import com.vaadin.client.widget.grid.events.ColumnReorderEvent;
import com.vaadin.client.widget.grid.events.ColumnReorderHandler;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent;
import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler;
+import com.vaadin.client.widget.grid.events.EditorCloseEvent;
+import com.vaadin.client.widget.grid.events.EditorEvent;
+import com.vaadin.client.widget.grid.events.EditorEventHandler;
import com.vaadin.client.widget.grid.events.FooterClickHandler;
import com.vaadin.client.widget.grid.events.FooterDoubleClickHandler;
import com.vaadin.client.widget.grid.events.FooterKeyDownHandler;
@@ -206,8 +214,10 @@ import com.vaadin.shared.util.SharedUtil;
* @author Vaadin Ltd
*/
public class Grid<T> extends ResizeComposite implements
- HasSelectionHandlers<T>, SubPartAware, DeferredWorker, HasWidgets,
- HasEnabled {
+ HasSelectionHandlers<T>, SubPartAware, DeferredWorker, Focusable,
+ com.google.gwt.user.client.ui.Focusable, HasWidgets, HasEnabled {
+
+ private static final String SELECT_ALL_CHECKBOX_CLASSNAME = "-select-all-checkbox";
/**
* Enum describing different sections of Grid.
@@ -1081,14 +1091,10 @@ public class Grid<T> extends ResizeComposite implements
}
completed = true;
- grid.getEditor().setErrorMessage(errorMessage);
-
- grid.getEditor().clearEditorColumnErrors();
- if (errorColumns != null) {
- for (Column<?, T> column : errorColumns) {
- grid.getEditor().setEditorColumnError(column, true);
- }
+ if (errorColumns == null) {
+ errorColumns = Collections.emptySet();
}
+ grid.getEditor().setEditorError(errorMessage, errorColumns);
}
@Override
@@ -1115,10 +1121,104 @@ public class Grid<T> extends ResizeComposite implements
}
/**
+ * A wrapper for native DOM events originating from Grid. In addition to the
+ * native event, contains a {@link CellReference} instance specifying which
+ * cell the event originated from.
+ *
+ * @since
+ * @param <T>
+ * The row type of the grid
+ */
+ public static class GridEvent<T> {
+ private Event event;
+ private EventCellReference<T> cell;
+
+ protected GridEvent(Event event, EventCellReference<T> cell) {
+ this.event = event;
+ this.cell = cell;
+ }
+
+ /**
+ * Returns the wrapped DOM event.
+ *
+ * @return the DOM event
+ */
+ public Event getDomEvent() {
+ return event;
+ }
+
+ /**
+ * Returns the Grid cell this event originated from.
+ *
+ * @return the event cell
+ */
+ public EventCellReference<T> getCell() {
+ return cell;
+ }
+
+ /**
+ * Returns the Grid instance this event originated from.
+ *
+ * @return the grid
+ */
+ public Grid<T> getGrid() {
+ return cell.getGrid();
+ }
+ }
+
+ /**
+ * A wrapper for native DOM events related to the {@link Editor Grid editor}
+ * .
+ *
+ * @since
+ * @param <T>
+ * the row type of the grid
+ */
+ public static class EditorDomEvent<T> extends GridEvent<T> {
+
+ protected EditorDomEvent(Event event, EventCellReference<T> cell) {
+ super(event, cell);
+ }
+
+ /**
+ * Returns the editor of the Grid this event originated from.
+ *
+ * @return the related editor instance
+ */
+ public Editor<T> getEditor() {
+ return getGrid().getEditor();
+ }
+
+ /**
+ * Returns the row index the editor is open at. If the editor is not
+ * open, returns -1.
+ *
+ * @return the index of the edited row or -1 if editor is not open
+ */
+ public int getRowIndex() {
+ return getEditor().rowIndex;
+ }
+
+ /**
+ * Returns the column index the editor was opened at. If the editor is
+ * not open, returns -1.
+ *
+ * @return the column index or -1 if editor is not open
+ */
+ public int getFocusedColumnIndex() {
+ return getEditor().focusedColumnIndex;
+ }
+ }
+
+ /**
* An editor UI for Grid rows. A single Grid row at a time can be opened for
* editing.
+ *
+ * @since
+ * @param <T>
+ * the row type of the grid
*/
- protected static class Editor<T> {
+ public static class Editor<T> {
public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER;
public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE;
@@ -1126,15 +1226,41 @@ public class Grid<T> extends ResizeComposite implements
private static final String ERROR_CLASS_NAME = "error";
private static final String NOT_EDITABLE_CLASS_NAME = "not-editable";
+ /**
+ * A handler for events related to the Grid editor. Responsible for
+ * opening, moving or closing the editor based on the received event.
+ *
+ * @since
+ * @author Vaadin Ltd
+ * @param <T>
+ * the row type of the grid
+ */
+ public interface EventHandler<T> {
+ /**
+ * Handles editor-related events in an appropriate way. Opens,
+ * moves, or closes the editor based on the given event.
+ *
+ * @param event
+ * the received event
+ * @return true if the event was handled and nothing else should be
+ * done, false otherwise
+ */
+ boolean handleEvent(EditorDomEvent<T> event);
+ }
+
protected enum State {
INACTIVE, ACTIVATING, BINDING, ACTIVE, SAVING
}
private Grid<T> grid;
private EditorHandler<T> handler;
+ private EventHandler<T> eventHandler = GWT
+ .create(DefaultEditorEventHandler.class);
private DivElement editorOverlay = DivElement.as(DOM.createDiv());
private DivElement cellWrapper = DivElement.as(DOM.createDiv());
+ private DivElement frozenCellWrapper = DivElement.as(DOM.createDiv());
+
private DivElement messageAndButtonsWrapper = DivElement.as(DOM
.createDiv());
@@ -1146,15 +1272,25 @@ public class Grid<T> extends ResizeComposite implements
private DivElement message = DivElement.as(DOM.createDiv());
private Map<Column<?, T>, Widget> columnToWidget = new HashMap<Column<?, T>, Widget>();
+ private List<HandlerRegistration> focusHandlers = new ArrayList<HandlerRegistration>();
private boolean enabled = false;
private State state = State.INACTIVE;
private int rowIndex = -1;
- private int columnIndex = -1;
+ private int focusedColumnIndex = -1;
private String styleName = null;
+ /*
+ * Used to track Grid horizontal scrolling
+ */
private HandlerRegistration scrollHandler;
+ /*
+ * Used to open editor once Grid has vertically scrolled to the proper
+ * position and data is available
+ */
+ private HandlerRegistration dataAvailableHandler;
+
private final Button saveButton;
private final Button cancelButton;
@@ -1209,6 +1345,7 @@ public class Grid<T> extends ResizeComposite implements
+ " remember to call success() or fail()?");
}
};
+
private final EditorRequestImpl.RequestCallback<T> bindRequestCallback = new EditorRequestImpl.RequestCallback<T>() {
@Override
public void onSuccess(EditorRequest<T> request) {
@@ -1216,10 +1353,7 @@ public class Grid<T> extends ResizeComposite implements
state = State.ACTIVE;
bindTimeout.cancel();
- assert rowIndex == request.getRowIndex() : "Request row index "
- + request.getRowIndex()
- + " did not match the saved row index " + rowIndex;
-
+ rowIndex = request.getRowIndex();
showOverlay();
}
}
@@ -1227,22 +1361,30 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void onError(EditorRequest<T> request) {
if (state == State.BINDING) {
- state = State.INACTIVE;
+ if (rowIndex == -1) {
+ doCancel();
+ } else {
+ state = State.ACTIVE;
+ }
bindTimeout.cancel();
// TODO show something in the DOM as well?
getLogger().warning(
"An error occurred while trying to show the "
+ "Grid editor");
- grid.getEscalator().setScrollLocked(Direction.VERTICAL,
- false);
- updateSelectionCheckboxesAsNeeded(true);
}
}
};
/** A set of all the columns that display an error flag. */
private final Set<Column<?, T>> columnErrors = new HashSet<Grid.Column<?, T>>();
+ private boolean buffered = true;
+
+ /** Original position of editor */
+ private double originalTop;
+ /** Original scroll position of grid when editor was opened */
+ private double originalScrollTop;
+ private RowHandle<T> pinnedRowHandle;
public Editor() {
saveButton = new Button();
@@ -1264,7 +1406,9 @@ public class Grid<T> extends ResizeComposite implements
});
}
- public void setErrorMessage(String errorMessage) {
+ public void setEditorError(String errorMessage,
+ Collection<Column<?, T>> errorColumns) {
+
if (errorMessage == null) {
message.removeFromParent();
} else {
@@ -1273,6 +1417,17 @@ public class Grid<T> extends ResizeComposite implements
messageWrapper.appendChild(message);
}
}
+ // In unbuffered mode only show message wrapper if there is an error
+ if (!isBuffered()) {
+ setMessageAndButtonsWrapperVisible(errorMessage != null);
+ }
+
+ if (state == State.ACTIVE || state == State.SAVING) {
+ for (Column<?, T> c : grid.getColumns()) {
+ grid.getEditor().setEditorColumnError(c,
+ errorColumns.contains(c));
+ }
+ }
}
public int getRow() {
@@ -1280,12 +1435,26 @@ public class Grid<T> extends ResizeComposite implements
}
/**
- * Equivalent to {@code editRow(rowIndex, -1)}.
+ * If a cell of this Grid had focus once this editRow call was
+ * triggered, the editor component at the previously focused column
+ * index will be focused.
+ *
+ * If a Grid cell was not focused prior to calling this method, it will
+ * be equivalent to {@code editRow(rowIndex, -1)}.
*
* @see #editRow(int, int)
*/
public void editRow(int rowIndex) {
- editRow(rowIndex, -1);
+ // Focus the last focused column in the editor iff grid or its child
+ // was focused before the edit request
+ Cell focusedCell = grid.cellFocusHandler.getFocusedCell();
+ Element focusedElement = WidgetUtil.getFocusedElement();
+ if (focusedCell != null && focusedElement != null
+ && grid.getElement().isOrHasChild(focusedElement)) {
+ editRow(rowIndex, focusedCell.getColumn());
+ } else {
+ editRow(rowIndex, -1);
+ }
}
/**
@@ -1302,28 +1471,41 @@ public class Grid<T> extends ResizeComposite implements
* @throws IllegalStateException
* if this editor is not enabled
* @throws IllegalStateException
- * if this editor is already in edit mode
+ * if this editor is already in edit mode and in buffered
+ * mode
*
* @since 7.5
*/
- public void editRow(int rowIndex, int columnIndex) {
+ public void editRow(final int rowIndex, int columnIndex) {
if (!enabled) {
throw new IllegalStateException(
"Cannot edit row: editor is not enabled");
}
if (state != State.INACTIVE) {
- throw new IllegalStateException(
- "Cannot edit row: editor already in edit mode");
+ if (isBuffered()) {
+ throw new IllegalStateException(
+ "Cannot edit row: editor already in edit mode");
+ }
}
this.rowIndex = rowIndex;
- this.columnIndex = columnIndex;
-
+ this.focusedColumnIndex = columnIndex;
state = State.ACTIVATING;
if (grid.getEscalator().getVisibleRowRange().contains(rowIndex)) {
- show();
+ show(rowIndex);
} else {
+ hideOverlay();
+ dataAvailableHandler = grid
+ .addDataAvailableHandler(new DataAvailableHandler() {
+ @Override
+ public void onDataAvailable(DataAvailableEvent event) {
+ if (event.getAvailableRows().contains(rowIndex)) {
+ show(rowIndex);
+ dataAvailableHandler.removeHandler();
+ }
+ }
+ });
grid.scrollToRow(rowIndex, ScrollDestination.MIDDLE);
}
}
@@ -1346,14 +1528,18 @@ public class Grid<T> extends ResizeComposite implements
throw new IllegalStateException(
"Cannot cancel edit: editor is not in edit mode");
}
- hideOverlay();
- grid.getEscalator().setScrollLocked(Direction.VERTICAL, false);
+ handler.cancel(new EditorRequestImpl<T>(grid, rowIndex, null));
+ doCancel();
+ }
- EditorRequest<T> request = new EditorRequestImpl<T>(grid, rowIndex,
- null);
- handler.cancel(request);
+ private void doCancel() {
+ hideOverlay();
state = State.INACTIVE;
+ rowIndex = -1;
+ focusedColumnIndex = -1;
+ grid.getEscalator().setScrollLocked(Direction.VERTICAL, false);
updateSelectionCheckboxesAsNeeded(true);
+ grid.fireEvent(new EditorCloseEvent(grid.eventCell));
}
private void updateSelectionCheckboxesAsNeeded(boolean isEnabled) {
@@ -1446,14 +1632,15 @@ public class Grid<T> extends ResizeComposite implements
this.enabled = enabled;
}
- protected void show() {
+ protected void show(int rowIndex) {
if (state == State.ACTIVATING) {
state = State.BINDING;
bindTimeout.schedule(BIND_TIMEOUT_MS);
EditorRequest<T> request = new EditorRequestImpl<T>(grid,
rowIndex, bindRequestCallback);
handler.bind(request);
- grid.getEscalator().setScrollLocked(Direction.VERTICAL, true);
+ grid.getEscalator().setScrollLocked(Direction.VERTICAL,
+ isBuffered());
updateSelectionCheckboxesAsNeeded(false);
}
}
@@ -1463,15 +1650,6 @@ public class Grid<T> extends ResizeComposite implements
assert this.grid == null : "Can only attach editor to Grid once";
this.grid = grid;
-
- grid.addDataAvailableHandler(new DataAvailableHandler() {
- @Override
- public void onDataAvailable(DataAvailableEvent event) {
- if (event.getAvailableRows().contains(rowIndex)) {
- show();
- }
- }
- });
}
protected State getState() {
@@ -1516,6 +1694,8 @@ public class Grid<T> extends ResizeComposite implements
* @since 7.5
*/
protected void showOverlay() {
+ // Ensure overlay is hidden initially
+ hideOverlay();
DivElement gridElement = DivElement.as(grid.getElement());
@@ -1526,19 +1706,38 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void onScroll(ScrollEvent event) {
updateHorizontalScrollPosition();
+ if (!isBuffered()) {
+ updateVerticalScrollPosition();
+ }
}
});
gridElement.appendChild(editorOverlay);
+ editorOverlay.appendChild(frozenCellWrapper);
editorOverlay.appendChild(cellWrapper);
editorOverlay.appendChild(messageAndButtonsWrapper);
+ int frozenColumns = grid.getVisibleFrozenColumnCount();
+ double frozenColumnsWidth = 0;
+ double cellHeight = 0;
+
for (int i = 0; i < tr.getCells().getLength(); i++) {
Element cell = createCell(tr.getCells().getItem(i));
-
- cellWrapper.appendChild(cell);
+ cellHeight = Math.max(cellHeight, WidgetUtil
+ .getRequiredHeightBoundingClientRectDouble(tr
+ .getCells().getItem(i)));
Column<?, T> column = grid.getVisibleColumn(i);
+
+ if (i < frozenColumns) {
+ frozenCellWrapper.appendChild(cell);
+ frozenColumnsWidth += WidgetUtil
+ .getRequiredWidthBoundingClientRectDouble(tr
+ .getCells().getItem(i));
+ } else {
+ cellWrapper.appendChild(cell);
+ }
+
if (column.isEditable()) {
Widget editor = getHandler().getWidget(column);
@@ -1547,7 +1746,28 @@ public class Grid<T> extends ResizeComposite implements
attachWidget(editor, cell);
}
- if (i == columnIndex) {
+ final int currentColumnIndex = i;
+ if (editor instanceof HasFocusHandlers) {
+ // Use a proper focus handler if available
+ focusHandlers.add(((HasFocusHandlers) editor)
+ .addFocusHandler(new FocusHandler() {
+ @Override
+ public void onFocus(FocusEvent event) {
+ focusedColumnIndex = currentColumnIndex;
+ }
+ }));
+ } else {
+ // Try sniffing for DOM focus events
+ focusHandlers.add(editor.addDomHandler(
+ new FocusHandler() {
+ @Override
+ public void onFocus(FocusEvent event) {
+ focusedColumnIndex = currentColumnIndex;
+ }
+ }, FocusEvent.getType()));
+ }
+
+ if (i == focusedColumnIndex) {
if (editor instanceof Focusable) {
((Focusable) editor).focus();
} else if (editor instanceof com.google.gwt.user.client.ui.Focusable) {
@@ -1557,17 +1777,70 @@ public class Grid<T> extends ResizeComposite implements
}
} else {
cell.addClassName(NOT_EDITABLE_CLASS_NAME);
+ cell.addClassName(tr.getCells().getItem(i).getClassName());
+ // If the focused or frozen stylename is present it should
+ // not be inherited by the editor cell as it is not useful
+ // in the editor and would look broken without additional
+ // style rules. This is a bit of a hack.
+ cell.removeClassName(grid.cellFocusStyleName);
+ cell.removeClassName("frozen");
+
+ if (column == grid.selectionColumn) {
+ // Duplicate selection column CheckBox
+
+ pinnedRowHandle = grid.getDataSource().getHandle(
+ grid.getDataSource().getRow(rowIndex));
+ pinnedRowHandle.pin();
+
+ // We need to duplicate the selection CheckBox for the
+ // editor overlay since the original one is hidden by
+ // the overlay
+ final CheckBox checkBox = GWT.create(CheckBox.class);
+ checkBox.setValue(grid.isSelected(pinnedRowHandle
+ .getRow()));
+ checkBox.sinkEvents(Event.ONCLICK);
+
+ checkBox.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ T row = pinnedRowHandle.getRow();
+ if (grid.isSelected(row)) {
+ grid.deselect(row);
+ } else {
+ grid.select(row);
+ }
+ }
+ });
+ attachWidget(checkBox, cell);
+ columnToWidget.put(column, checkBox);
+
+ // Only enable CheckBox in non-buffered mode
+ checkBox.setEnabled(!isBuffered());
+
+ } else if (!(column.getRenderer() instanceof WidgetRenderer)) {
+ // Copy non-widget content directly
+ cell.setInnerHTML(tr.getCells().getItem(i)
+ .getInnerHTML());
+ }
}
}
+ setBounds(frozenCellWrapper, 0, 0, frozenColumnsWidth, 0);
+ setBounds(cellWrapper, frozenColumnsWidth, 0, tr.getOffsetWidth()
+ - frozenColumnsWidth, cellHeight);
+
// Only add these elements once
if (!messageAndButtonsWrapper.isOrHasChild(messageWrapper)) {
messageAndButtonsWrapper.appendChild(messageWrapper);
messageAndButtonsWrapper.appendChild(buttonsWrapper);
}
- attachWidget(saveButton, buttonsWrapper);
- attachWidget(cancelButton, buttonsWrapper);
+ if (isBuffered()) {
+ attachWidget(saveButton, buttonsWrapper);
+ attachWidget(cancelButton, buttonsWrapper);
+ }
+
+ setMessageAndButtonsWrapperVisible(isBuffered());
updateHorizontalScrollPosition();
@@ -1579,9 +1852,11 @@ public class Grid<T> extends ResizeComposite implements
int gridTop = gridElement.getAbsoluteTop();
double overlayTop = rowTop + bodyTop - gridTop;
- if (buttonsShouldBeRenderedBelow(tr)) {
+ originalScrollTop = grid.getScrollTop();
+ if (!isBuffered() || buttonsShouldBeRenderedBelow(tr)) {
// Default case, editor buttons are below the edited row
editorOverlay.getStyle().setTop(overlayTop, Unit.PX);
+ originalTop = overlayTop;
editorOverlay.getStyle().clearBottom();
} else {
// Move message and buttons wrapper on top of cell wrapper if
@@ -1614,6 +1889,20 @@ public class Grid<T> extends ResizeComposite implements
}
protected void hideOverlay() {
+ if (editorOverlay.getParentElement() == null) {
+ return;
+ }
+
+ if (pinnedRowHandle != null) {
+ pinnedRowHandle.unpin();
+ pinnedRowHandle = null;
+ }
+
+ for (HandlerRegistration r : focusHandlers) {
+ r.removeHandler();
+ }
+ focusHandlers.clear();
+
for (Widget w : columnToWidget.values()) {
setParent(w, null);
}
@@ -1624,11 +1913,16 @@ public class Grid<T> extends ResizeComposite implements
editorOverlay.removeAllChildren();
cellWrapper.removeAllChildren();
+ frozenCellWrapper.removeAllChildren();
editorOverlay.removeFromParent();
scrollHandler.removeHandler();
clearEditorColumnErrors();
+
+ if (focusedColumnIndex != -1) {
+ grid.focusCell(rowIndex, focusedColumnIndex);
+ }
}
protected void setStylePrimaryName(String primaryName) {
@@ -1636,6 +1930,7 @@ public class Grid<T> extends ResizeComposite implements
editorOverlay.removeClassName(styleName);
cellWrapper.removeClassName(styleName + "-cells");
+ frozenCellWrapper.removeClassName(styleName + "-cells");
messageAndButtonsWrapper.removeClassName(styleName + "-footer");
messageWrapper.removeClassName(styleName + "-message");
@@ -1648,6 +1943,7 @@ public class Grid<T> extends ResizeComposite implements
editorOverlay.setClassName(styleName);
cellWrapper.setClassName(styleName + "-cells");
+ frozenCellWrapper.setClassName(styleName + "-cells frozen");
messageAndButtonsWrapper.setClassName(styleName + "-footer");
messageWrapper.setClassName(styleName + "-message");
@@ -1698,7 +1994,37 @@ public class Grid<T> extends ResizeComposite implements
private void updateHorizontalScrollPosition() {
double scrollLeft = grid.getScrollLeft();
- cellWrapper.getStyle().setLeft(-scrollLeft, Unit.PX);
+ cellWrapper.getStyle().setLeft(
+ frozenCellWrapper.getOffsetWidth() - scrollLeft, Unit.PX);
+ }
+
+ /**
+ * Moves the editor overlay on scroll so that it stays on top of the
+ * edited row. This will also snap the editor to top or bottom of the
+ * row container if the edited row is scrolled out of the visible area.
+ */
+ private void updateVerticalScrollPosition() {
+ double newScrollTop = grid.getScrollTop();
+
+ int gridTop = grid.getElement().getAbsoluteTop();
+ int editorHeight = editorOverlay.getOffsetHeight();
+
+ Escalator escalator = grid.getEscalator();
+ TableSectionElement header = escalator.getHeader().getElement();
+ int footerTop = escalator.getFooter().getElement().getAbsoluteTop();
+ int headerBottom = header.getAbsoluteBottom();
+
+ double newTop = originalTop - (newScrollTop - originalScrollTop);
+
+ if (newTop + gridTop < headerBottom) {
+ // Snap editor to top of the row container
+ newTop = header.getOffsetHeight();
+ } else if (newTop + gridTop > footerTop - editorHeight) {
+ // Snap editor to the bottom of the row container
+ newTop = footerTop - editorHeight - gridTop;
+ }
+
+ editorOverlay.getStyle().setTop(newTop, Unit.PX);
}
protected void setGridEnabled(boolean enabled) {
@@ -1777,6 +2103,44 @@ public class Grid<T> extends ResizeComposite implements
public boolean isEditorColumnError(Column<?, T> column) {
return columnErrors.contains(column);
}
+
+ public void setBuffered(boolean buffered) {
+ this.buffered = buffered;
+ setMessageAndButtonsWrapperVisible(buffered);
+ }
+
+ public boolean isBuffered() {
+ return buffered;
+ }
+
+ private void setMessageAndButtonsWrapperVisible(boolean visible) {
+ if (visible) {
+ messageAndButtonsWrapper.getStyle().clearDisplay();
+ } else {
+ messageAndButtonsWrapper.getStyle().setDisplay(Display.NONE);
+ }
+ }
+
+ /**
+ * Sets the event handler for this Editor.
+ *
+ * @since
+ * @param handler
+ * the new event handler
+ */
+ public void setEventHandler(EventHandler<T> handler) {
+ eventHandler = handler;
+ }
+
+ /**
+ * Returns the event handler of this Editor.
+ *
+ * @since
+ * @return the current event handler
+ */
+ public EventHandler<T> getEventHandler() {
+ return eventHandler;
+ }
}
public static abstract class AbstractGridKeyEvent<HANDLER extends AbstractGridKeyEventHandler>
@@ -2351,6 +2715,7 @@ public class Grid<T> extends ResizeComposite implements
private boolean initDone = false;
private boolean selected = false;
+ private CheckBox selectAllCheckBox;
SelectionColumn(final Renderer<Boolean> selectColumnRenderer) {
super(selectColumnRenderer);
@@ -2375,41 +2740,57 @@ public class Grid<T> extends ResizeComposite implements
* exist.
*/
final SelectionModel.Multi<T> model = (Multi<T>) getSelectionModel();
- final CheckBox checkBox = GWT.create(CheckBox.class);
- checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
- @Override
- public void onValueChange(ValueChangeEvent<Boolean> event) {
- if (event.getValue()) {
- fireEvent(new SelectAllEvent<T>(model));
- selected = true;
- } else {
- model.deselectAll();
- selected = false;
- }
- }
- });
- checkBox.setValue(selected);
- selectionCell.setWidget(checkBox);
- // Select all with space when "select all" cell is active
- addHeaderKeyUpHandler(new HeaderKeyUpHandler() {
- @Override
- public void onKeyUp(GridKeyUpEvent event) {
- if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) {
- return;
- }
- HeaderRow targetHeaderRow = getHeader().getRow(
- event.getFocusedCell().getRowIndex());
- if (!targetHeaderRow.isDefault()) {
- return;
+ if (selectAllCheckBox == null) {
+ selectAllCheckBox = GWT.create(CheckBox.class);
+ selectAllCheckBox.setStylePrimaryName(getStylePrimaryName()
+ + SELECT_ALL_CHECKBOX_CLASSNAME);
+ selectAllCheckBox
+ .addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+
+ @Override
+ public void onValueChange(
+ ValueChangeEvent<Boolean> event) {
+ if (event.getValue()) {
+ fireEvent(new SelectAllEvent<T>(model));
+ selected = true;
+ } else {
+ model.deselectAll();
+ selected = false;
+ }
+ }
+ });
+ selectAllCheckBox.setValue(selected);
+
+ // Select all with space when "select all" cell is active
+ addHeaderKeyUpHandler(new HeaderKeyUpHandler() {
+ @Override
+ public void onKeyUp(GridKeyUpEvent event) {
+ if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) {
+ return;
+ }
+ HeaderRow targetHeaderRow = getHeader().getRow(
+ event.getFocusedCell().getRowIndex());
+ if (!targetHeaderRow.isDefault()) {
+ return;
+ }
+ if (event.getFocusedCell().getColumn() == SelectionColumn.this) {
+ // Send events to ensure state is updated
+ selectAllCheckBox.setValue(
+ !selectAllCheckBox.getValue(), true);
+ }
}
- if (event.getFocusedCell().getColumn() == SelectionColumn.this) {
- // Send events to ensure row selection state is
- // updated
- checkBox.setValue(!checkBox.getValue(), true);
+ });
+ } else {
+ for (HeaderRow row : header.getRows()) {
+ if (row.getCell(this).getType() == GridStaticCellType.WIDGET) {
+ // Detach from old header.
+ row.getCell(this).setText("");
}
}
- });
+ }
+
+ selectionCell.setWidget(selectAllCheckBox);
}
@Override
@@ -2471,7 +2852,6 @@ public class Grid<T> extends ResizeComposite implements
super.setEditable(editable);
return this;
}
-
}
/**
@@ -2736,7 +3116,9 @@ public class Grid<T> extends ResizeComposite implements
for (Column<?, T> column : visibleColumns) {
final double widthAsIs = column.getWidth();
final boolean isFixedWidth = widthAsIs >= 0;
- final double widthFixed = Math.max(widthAsIs,
+ // Check for max width just to be sure we don't break the limits
+ final double widthFixed = Math.max(
+ Math.min(getMaxWidth(column), widthAsIs),
column.getMinimumWidth());
defaultExpandRatios = defaultExpandRatios
&& (column.getExpandRatio() == -1 || column == selectionColumn);
@@ -2755,8 +3137,9 @@ public class Grid<T> extends ResizeComposite implements
for (Column<?, T> column : nonFixedColumns) {
final int expandRatio = (defaultExpandRatios ? 1 : column
.getExpandRatio());
- final double newWidth = column.getWidthActual();
final double maxWidth = getMaxWidth(column);
+ final double newWidth = Math.min(maxWidth,
+ column.getWidthActual());
boolean shouldExpand = newWidth < maxWidth && expandRatio > 0
&& column != selectionColumn;
if (shouldExpand) {
@@ -2775,6 +3158,10 @@ public class Grid<T> extends ResizeComposite implements
double pixelsToDistribute = escalator.getInnerWidth()
- reservedPixels;
if (pixelsToDistribute <= 0 || totalRatios <= 0) {
+ if (pixelsToDistribute <= 0) {
+ // Set column sizes for expanding columns
+ setColumnSizes(columnSizes);
+ }
return;
}
@@ -3222,7 +3609,6 @@ public class Grid<T> extends ResizeComposite implements
clickOutsideToCloseHandlerRegistration = Event
.addNativePreviewHandler(clickOutsideToCloseHandler);
}
- openCloseButton.setHeight("");
}
/**
@@ -3251,46 +3637,6 @@ public class Grid<T> extends ResizeComposite implements
return content.getParent() == rootContainer;
}
- /**
- * Adds or moves the given widget to the end of the sidebar.
- *
- * @param widget
- * the widget to add or move
- */
- public void add(Widget widget) {
- content.add(widget);
- updateVisibility();
- }
-
- /**
- * Removes the given widget from the sidebar.
- *
- * @param widget
- * the widget to remove
- */
- public void remove(Widget widget) {
- content.remove(widget);
- // updateVisibility is called by remove listener
- }
-
- /**
- * Inserts given widget to the given index inside the sidebar. If the
- * widget is already in the sidebar, then it is moved to the new index.
- * <p>
- * See
- * {@link FlowPanel#insert(com.google.gwt.user.client.ui.IsWidget, int)}
- * for further details.
- *
- * @param widget
- * the widget to insert
- * @param beforeIndex
- * 0-based index position for the widget.
- */
- public void insert(Widget widget, int beforeIndex) {
- content.insert(widget, beforeIndex);
- updateVisibility();
- }
-
@Override
public void setStylePrimaryName(String styleName) {
super.setStylePrimaryName(styleName);
@@ -3536,10 +3882,6 @@ public class Grid<T> extends ResizeComposite implements
private final AutoColumnWidthsRecalculator autoColumnWidthsRecalculator = new AutoColumnWidthsRecalculator();
private boolean enabled = true;
- private double lastTouchEventTime = 0;
- private int lastTouchEventX = -1;
- private int lastTouchEventY = -1;
- private int lastTouchEventRow = -1;
private DetailsGenerator detailsGenerator = DetailsGenerator.NULL;
private GridSpacerUpdater gridSpacerUpdater = new GridSpacerUpdater();
@@ -3725,8 +4067,8 @@ public class Grid<T> extends ResizeComposite implements
}
private boolean isSidebarOnDraggedRow() {
- return eventCell.getRowIndex() == 0 && getSidebar().isInDOM()
- && !getSidebar().isOpen();
+ return eventCell.getRowIndex() == 0 && sidebar.isInDOM()
+ && !sidebar.isOpen();
}
/**
@@ -3736,8 +4078,7 @@ public class Grid<T> extends ResizeComposite implements
private double getSidebarBoundaryComparedTo(double left) {
if (isSidebarOnDraggedRow()) {
double absoluteLeft = left + getElement().getAbsoluteLeft();
- double sidebarLeft = getSidebar().getElement()
- .getAbsoluteLeft();
+ double sidebarLeft = sidebar.getElement().getAbsoluteLeft();
double diff = absoluteLeft - sidebarLeft;
if (diff > 0) {
@@ -4236,6 +4577,16 @@ public class Grid<T> extends ResizeComposite implements
return this;
}
+ /**
+ * Returns the current header caption for this column
+ *
+ * @since
+ * @return the header caption string
+ */
+ public String getHeaderCaption() {
+ return headerCaption;
+ }
+
private void updateHeader() {
HeaderRow row = grid.getHeader().getDefaultRow();
if (row != null) {
@@ -4937,7 +5288,7 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
for (FlyweightCell cell : cellsToDetach) {
- Renderer renderer = findRenderer(cell);
+ Renderer<?> renderer = findRenderer(cell);
if (renderer instanceof WidgetRenderer) {
try {
Widget w = WidgetUtil.findWidget(cell.getElement()
@@ -4967,7 +5318,7 @@ public class Grid<T> extends ResizeComposite implements
// any more
rowReference.set(rowIndex, null, row.getElement());
for (FlyweightCell cell : detachedCells) {
- Renderer renderer = findRenderer(cell);
+ Renderer<?> renderer = findRenderer(cell);
if (renderer instanceof ComplexRenderer) {
try {
Column<?, T> column = getVisibleColumn(cell.getColumn());
@@ -5211,7 +5562,7 @@ public class Grid<T> extends ResizeComposite implements
sinkEvents(getHeader().getConsumedEvents());
sinkEvents(Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.KEYUP,
BrowserEvents.KEYPRESS, BrowserEvents.DBLCLICK,
- BrowserEvents.MOUSEDOWN));
+ BrowserEvents.MOUSEDOWN, BrowserEvents.CLICK));
// Make ENTER and SHIFT+ENTER in the header perform sorting
addHeaderKeyUpHandler(new HeaderKeyUpHandler() {
@@ -5353,6 +5704,35 @@ public class Grid<T> extends ResizeComposite implements
}
/**
+ * Try to focus a cell by row and column index. Purely internal method.
+ *
+ * @param rowIndex
+ * row index from Editor
+ * @param columnIndex
+ * column index from Editor
+ */
+ void focusCell(int rowIndex, int columnIndex) {
+ RowReference<T> row = new RowReference<T>(this);
+ Range visibleRows = escalator.getVisibleRowRange();
+
+ TableRowElement rowElement;
+ if (visibleRows.contains(rowIndex)) {
+ rowElement = escalator.getBody().getRowElement(rowIndex);
+ } else {
+ getLogger().warning("Row index was not among visible row range");
+ return;
+ }
+ row.set(rowIndex, dataSource.getRow(rowIndex), rowElement);
+
+ CellReference<T> cell = new CellReference<T>(row);
+ cell.set(columnIndex, columnIndex, getVisibleColumn(columnIndex));
+
+ cellFocusHandler.setCellFocus(cell);
+
+ WidgetUtil.focus(getElement());
+ }
+
+ /**
* Refreshes all header rows
*/
void refreshHeader() {
@@ -5883,10 +6263,23 @@ public class Grid<T> extends ResizeComposite implements
return footer.isVisible();
}
- protected Editor<T> getEditor() {
+ public Editor<T> getEditor() {
return editor;
}
+ /**
+ * Add handler for editor open/move/close events
+ *
+ * @param handler
+ * editor handler object
+ * @return a {@link HandlerRegistration} object that can be used to remove
+ * the event handler
+ */
+ public HandlerRegistration addEditorEventHandler(EditorEventHandler handler) {
+ return addHandler(handler, EditorEvent.TYPE);
+
+ }
+
protected Escalator getEscalator() {
return escalator;
}
@@ -6051,7 +6444,12 @@ public class Grid<T> extends ResizeComposite implements
}
private void updateFrozenColumns() {
- int numberOfColumns = frozenColumnCount;
+ escalator.getColumnConfiguration().setFrozenColumnCount(
+ getVisibleFrozenColumnCount());
+ }
+
+ private int getVisibleFrozenColumnCount() {
+ int numberOfColumns = getFrozenColumnCount();
// for the escalator the hidden columns are not in the frozen column
// count, but for grid they are. thus need to convert the index
@@ -6066,9 +6464,7 @@ public class Grid<T> extends ResizeComposite implements
} else if (selectionColumn != null) {
numberOfColumns++;
}
-
- escalator.getColumnConfiguration()
- .setFrozenColumnCount(numberOfColumns);
+ return numberOfColumns;
}
/**
@@ -6347,6 +6743,14 @@ public class Grid<T> extends ResizeComposite implements
return;
}
+ String eventType = event.getType();
+
+ if (eventType.equals(BrowserEvents.FOCUS)
+ || eventType.equals(BrowserEvents.BLUR)) {
+ super.onBrowserEvent(event);
+ return;
+ }
+
EventTarget target = event.getEventTarget();
if (!Element.is(target) || isOrContainsInSpacer(Element.as(target))) {
@@ -6357,7 +6761,6 @@ public class Grid<T> extends ResizeComposite implements
RowContainer container = escalator.findRowContainer(e);
Cell cell;
- String eventType = event.getType();
if (container == null) {
if (eventType.equals(BrowserEvents.KEYDOWN)
|| eventType.equals(BrowserEvents.KEYUP)
@@ -6387,7 +6790,7 @@ public class Grid<T> extends ResizeComposite implements
eventCell.set(cell, getSectionFromContainer(container));
// Editor can steal focus from Grid and is still handled
- if (handleEditorEvent(event, container)) {
+ if (isEditorEnabled() && handleEditorEvent(event, container)) {
return;
}
@@ -6465,50 +6868,8 @@ public class Grid<T> extends ResizeComposite implements
}
private boolean handleEditorEvent(Event event, RowContainer container) {
-
- final boolean closeEvent = event.getTypeInt() == Event.ONKEYDOWN
- && event.getKeyCode() == Editor.KEYCODE_HIDE;
-
- double now = Duration.currentTimeMillis();
- int currentX = WidgetUtil.getTouchOrMouseClientX(event);
- int currentY = WidgetUtil.getTouchOrMouseClientY(event);
-
- final boolean validTouchOpenEvent = event.getTypeInt() == Event.ONTOUCHEND
- && now - lastTouchEventTime < 500
- && lastTouchEventRow == eventCell.getRowIndex()
- && Math.abs(lastTouchEventX - currentX) < 20
- && Math.abs(lastTouchEventY - currentY) < 20;
-
- final boolean openEvent = event.getTypeInt() == Event.ONDBLCLICK
- || (event.getTypeInt() == Event.ONKEYDOWN && event.getKeyCode() == Editor.KEYCODE_SHOW)
- || validTouchOpenEvent;
-
- if (event.getTypeInt() == Event.ONTOUCHSTART) {
- lastTouchEventX = currentX;
- lastTouchEventY = currentY;
- }
-
- if (event.getTypeInt() == Event.ONTOUCHEND) {
- lastTouchEventTime = now;
- lastTouchEventRow = eventCell.getRowIndex();
- }
-
- if (editor.getState() != Editor.State.INACTIVE) {
- if (closeEvent) {
- editor.cancel();
- FocusUtil.setFocus(this, true);
- }
- return true;
- }
-
- if (container == escalator.getBody() && editor.isEnabled() && openEvent) {
- editor.editRow(eventCell.getRowIndex(),
- eventCell.getColumnIndexDOM());
- event.preventDefault();
- return true;
- }
-
- return false;
+ return getEditor().getEventHandler().handleEvent(
+ new EditorDomEvent<T>(event, getEventCell()));
}
private boolean handleRendererEvent(Event event, RowContainer container) {
@@ -6703,11 +7064,21 @@ public class Grid<T> extends ResizeComposite implements
if (args.getIndicesLength() == 0) {
return editor.editorOverlay;
- } else if (args.getIndicesLength() == 1
- && args.getIndex(0) < columns.size()) {
- escalator
- .scrollToColumn(args.getIndex(0), ScrollDestination.ANY, 0);
- return editor.getWidget(columns.get(args.getIndex(0))).getElement();
+ } else if (args.getIndicesLength() == 1) {
+ int index = args.getIndex(0);
+ if (index >= columns.size()) {
+ return null;
+ }
+
+ escalator.scrollToColumn(index, ScrollDestination.ANY, 0);
+ Widget widget = editor.getWidget(columns.get(index));
+
+ if (widget != null) {
+ return widget.getElement();
+ }
+
+ // No widget for the column.
+ return null;
}
return null;
@@ -6863,12 +7234,12 @@ public class Grid<T> extends ResizeComposite implements
* if the current selection model is not an instance of
* {@link SelectionModel.Single} or {@link SelectionModel.Multi}
*/
- @SuppressWarnings("unchecked")
public boolean select(T row) {
if (selectionModel instanceof SelectionModel.Single<?>) {
return ((SelectionModel.Single<T>) selectionModel).select(row);
} else if (selectionModel instanceof SelectionModel.Multi<?>) {
- return ((SelectionModel.Multi<T>) selectionModel).select(row);
+ return ((SelectionModel.Multi<T>) selectionModel)
+ .select(Collections.singleton(row));
} else {
throw new IllegalStateException("Unsupported selection model");
}
@@ -6888,12 +7259,12 @@ public class Grid<T> extends ResizeComposite implements
* if the current selection model is not an instance of
* {@link SelectionModel.Single} or {@link SelectionModel.Multi}
*/
- @SuppressWarnings("unchecked")
public boolean deselect(T row) {
if (selectionModel instanceof SelectionModel.Single<?>) {
return ((SelectionModel.Single<T>) selectionModel).deselect(row);
} else if (selectionModel instanceof SelectionModel.Multi<?>) {
- return ((SelectionModel.Multi<T>) selectionModel).deselect(row);
+ return ((SelectionModel.Multi<T>) selectionModel)
+ .deselect(Collections.singleton(row));
} else {
throw new IllegalStateException("Unsupported selection model");
}
@@ -7670,6 +8041,12 @@ public class Grid<T> extends ResizeComposite implements
if (escalator.getInnerWidth() != autoColumnWidthsRecalculator.lastCalculatedInnerWidth) {
recalculateColumnWidths();
}
+
+ // Vertical resizing could make editor positioning invalid so it
+ // needs to be recalculated on resize
+ if (isEditorActive()) {
+ editor.updateVerticalScrollPosition();
+ }
}
});
}
@@ -7775,15 +8152,15 @@ public class Grid<T> extends ResizeComposite implements
@Override
protected void doAttachChildren() {
- if (getSidebar().getParent() == this) {
- onAttach(getSidebar());
+ if (sidebar.getParent() == this) {
+ onAttach(sidebar);
}
}
@Override
protected void doDetachChildren() {
- if (getSidebar().getParent() == this) {
- onDetach(getSidebar());
+ if (sidebar.getParent() == this) {
+ onDetach(sidebar);
}
}
@@ -7815,6 +8192,10 @@ public class Grid<T> extends ResizeComposite implements
"Details generator may not be null");
}
+ for (Integer index : visibleDetails) {
+ setDetailsVisible(index, false);
+ }
+
this.detailsGenerator = detailsGenerator;
// this will refresh all visible spacers
@@ -7846,6 +8227,10 @@ public class Grid<T> extends ResizeComposite implements
* @see #isDetailsVisible(int)
*/
public void setDetailsVisible(int rowIndex, boolean visible) {
+ if (DetailsGenerator.NULL.equals(detailsGenerator)) {
+ return;
+ }
+
Integer rowIndexInteger = Integer.valueOf(rowIndex);
/*
@@ -7904,19 +8289,6 @@ public class Grid<T> extends ResizeComposite implements
}
/**
- * Returns the sidebar for this grid.
- * <p>
- * The grid's sidebar shows the column hiding options for those columns that
- * have been set as {@link Column#setHidable(boolean) hidable}.
- *
- * @since 7.5.0
- * @return the sidebar widget for this grid
- */
- private Sidebar getSidebar() {
- return sidebar;
- }
-
- /**
* Gets the customizable menu bar that is by default used for toggling
* column hidability. The application developer is allowed to add their
* custom items to the end of the menu, but should try to avoid modifying
@@ -7962,6 +8334,54 @@ public class Grid<T> extends ResizeComposite implements
}
}
+ @Override
+ public int getTabIndex() {
+ return FocusUtil.getTabIndex(this);
+ }
+
+ @Override
+ public void setAccessKey(char key) {
+ FocusUtil.setAccessKey(this, key);
+ }
+
+ @Override
+ public void setFocus(boolean focused) {
+ FocusUtil.setFocus(this, focused);
+ }
+
+ @Override
+ public void setTabIndex(int index) {
+ FocusUtil.setTabIndex(this, index);
+ }
+
+ @Override
+ public void focus() {
+ setFocus(true);
+ }
+
+ /**
+ * Sets the buffered editor mode.
+ *
+ * @since 7.6
+ * @param editorUnbuffered
+ * <code>true</code> to enable buffered editor,
+ * <code>false</code> to disable it
+ */
+ public void setEditorBuffered(boolean editorBuffered) {
+ editor.setBuffered(editorBuffered);
+ }
+
+ /**
+ * Gets the buffered editor mode.
+ *
+ * @since 7.6
+ * @return <code>true</code> if buffered editor is enabled,
+ * <code>false</code> otherwise
+ */
+ public boolean isEditorBuffered() {
+ return editor.isBuffered();
+ }
+
/**
* Returns the {@link EventCellReference} for the latest event fired from
* this Grid.
@@ -7974,4 +8394,26 @@ public class Grid<T> extends ResizeComposite implements
public EventCellReference<T> getEventCell() {
return eventCell;
}
+
+ /**
+ * Returns a CellReference for the cell to which the given element belongs
+ * to.
+ *
+ * @since 7.6
+ * @param element
+ * Element to find from the cell's content.
+ * @return CellReference or <code>null</code> if cell was not found.
+ */
+ public CellReference<T> getCellReference(Element element) {
+ RowContainer container = getEscalator().findRowContainer(element);
+ if (container != null) {
+ Cell cell = container.getCell(element);
+ if (cell != null) {
+ EventCellReference<T> cellRef = new EventCellReference<T>(this);
+ cellRef.set(cell, getSectionFromContainer(container));
+ return cellRef;
+ }
+ }
+ return null;
+ }
}
diff --git a/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java b/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java
index 62b727e5f5..24bf9b6558 100644
--- a/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java
+++ b/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java
@@ -56,6 +56,8 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase {
private static final String ANDROID_MOTOROLA_3_0 = "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13";
private static final String ANDROID_GALAXY_NEXUS_4_0_4_CHROME = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19";
+ private static final String EDGE_WINDOWS_10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240";
+
public void testSafari3() {
VBrowserDetails bd = new VBrowserDetails(SAFARI3_WINDOWS);
assertWebKit(bd);
@@ -423,6 +425,14 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase {
assertWindows(bd, true);
}
+ public void testEdgeWindows10() {
+ VBrowserDetails bd = new VBrowserDetails(EDGE_WINDOWS_10);
+ assertEdge(bd);
+ assertBrowserMajorVersion(bd, 12);
+ assertBrowserMinorVersion(bd, 10240);
+ assertWindows(bd, false);
+ }
+
/*
* Helper methods below
*/
@@ -484,6 +494,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase {
assertFalse(browserDetails.isIE());
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
+ assertFalse(browserDetails.isEdge());
}
private void assertChrome(VBrowserDetails browserDetails) {
@@ -493,6 +504,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase {
assertFalse(browserDetails.isIE());
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
+ assertFalse(browserDetails.isEdge());
}
private void assertIE(VBrowserDetails browserDetails) {
@@ -502,6 +514,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase {
assertTrue(browserDetails.isIE());
assertFalse(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
+ assertFalse(browserDetails.isEdge());
}
private void assertOpera(VBrowserDetails browserDetails) {
@@ -511,6 +524,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase {
assertFalse(browserDetails.isIE());
assertTrue(browserDetails.isOpera());
assertFalse(browserDetails.isSafari());
+ assertFalse(browserDetails.isEdge());
}
private void assertSafari(VBrowserDetails browserDetails) {
@@ -520,6 +534,17 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase {
assertFalse(browserDetails.isIE());
assertFalse(browserDetails.isOpera());
assertTrue(browserDetails.isSafari());
+ assertFalse(browserDetails.isEdge());
+ }
+
+ private void assertEdge(VBrowserDetails browserDetails) {
+ // Browser
+ assertFalse(browserDetails.isFirefox());
+ assertFalse(browserDetails.isChrome());
+ assertFalse(browserDetails.isIE());
+ assertFalse(browserDetails.isOpera());
+ assertFalse(browserDetails.isSafari());
+ assertTrue(browserDetails.isEdge());
}
private void assertMacOSX(VBrowserDetails browserDetails) {
diff --git a/eclipse/Super Development Mode (vaadin).launch b/eclipse/Super Development Mode (vaadin).launch
index 361a456e96..b03337e5ff 100644
--- a/eclipse/Super Development Mode (vaadin).launch
+++ b/eclipse/Super Development Mode (vaadin).launch
@@ -23,5 +23,5 @@
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.codeserver.CodeServer"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-noprecompile -strict -bindAddress 0.0.0.0 com.vaadin.DefaultWidgetSet com.vaadin.tests.widgetset.TestingWidgetSet"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="vaadin"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512M -XX:MaxPermSize=256M"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx1G -XX:MaxPermSize=256M"/>
</launchConfiguration>
diff --git a/push/ivy.xml b/push/ivy.xml
index faf96818e1..180eeac7b8 100644
--- a/push/ivy.xml
+++ b/push/ivy.xml
@@ -3,7 +3,7 @@
<!-- Keep the version number in sync with build.xml -->
<!ENTITY atmosphere.runtime.version "2.2.7.vaadin1">
- <!ENTITY atmosphere.js.version "2.2.6.vaadin4">
+ <!ENTITY atmosphere.js.version "2.2.6.vaadin5">
]>
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
diff --git a/scripts/DeployHelpers.py b/scripts/DeployHelpers.py
index 2c879088ff..12c7baaaec 100644
--- a/scripts/DeployHelpers.py
+++ b/scripts/DeployHelpers.py
@@ -12,14 +12,51 @@ except Exception as e:
from requests.auth import HTTPDigestAuth
from os.path import join, expanduser, basename
from BuildHelpers import parser, getArgs
+from time import sleep
parser.add_argument("--deployUrl", help="Wildfly management URL")
parser.add_argument("--deployUser", help="Deployment user", default=None)
parser.add_argument("--deployPass", help="Deployment password", default=None)
+serverUp = None
+
+def testServer():
+ global serverUp
+
+ if serverUp is not None:
+ return serverUp
+
+ print("Checking server status")
+ i = 0
+ request = {"operation" : "read-attribute", "name" : "server-state"}
+ serverUp = False
+ while not serverUp and i < 2:
+ try:
+ print("Trying on url %s" % (getUrl()))
+ result = doPostJson(url=getUrl(), auth=getAuth(), data=json.dumps(request))
+ response = result.json()
+ if "outcome" not in response or response["outcome"] != "success":
+ # Failure
+ raise Exception(response)
+ elif "result" not in response or response["result"] != "running":
+ # Another failure
+ raise Exception(response)
+ # All OK
+ serverUp = True
+ print("Got server connection.")
+ except Exception as e:
+ print("Exception while checking server state: ", e)
+ print("Server connection failed, retrying in 5 seconds.")
+ i = i + 1
+ sleep(5)
+ return serverUp
+
# Helper for handling the full deployment
# name should end with .war
def deployWar(warFile, name=None):
+ if not testServer():
+ raise Exception("Server not up. Skipping deployment.")
+ return
if name is None:
name = basename(warFile).replace('.war', "-%s.war" % (getArgs().version.split('-')[0]))
diff --git a/scripts/GenerateBuildReport.py b/scripts/GenerateBuildReport.py
index 8ee2472133..eafdb39430 100644
--- a/scripts/GenerateBuildReport.py
+++ b/scripts/GenerateBuildReport.py
@@ -15,6 +15,7 @@ content = """<html>
<body>
<table>
<tr><td><a href="https://dev.vaadin.com/milestone?action=new">Create milestone for next release</a></td></tr>
+<tr><td><a href="https://dev.vaadin.com/query?status=closed&component=Core+Framework&resolution=fixed&milestone=!Vaadin {version}&col=id&col=summary&col=component&col=status&col=type&col=priority&col=milestone&order=priority">Closed fixed tickets without milestone {version}</a></td></tr>
<tr><td><a href="https://dev.vaadin.com/query?status=closed&component=Core+Framework&resolution=fixed&milestone=Vaadin {version}&col=id&col=summary&col=component&col=milestone&col=status&col=type">Closed tickets with milestone {version}</a></td></tr>
<tr><td><a href="https://dev.vaadin.com/query?status=pending-release&component=Core+Framework&resolution=fixed&milestone=Vaadin {version}&col=id&col=summary&col=component&col=milestone&col=status&col=type">Pending-release tickets with milestone {version}</a></td></tr>
<tr><td><a href="https://dev.vaadin.com/query?status=pending-release&milestone=">Pending-release tickets without milestone</a></td></tr>
@@ -24,8 +25,8 @@ content = """<html>
try:
p1 = subprocess.Popen(['find', '.', '-name', '*.java'], stdout=subprocess.PIPE)
- p2 = subprocess.Popen(['xargs', 'egrep', '@since ?$'], stdin=p1.stdout, stdout=subprocess.PIPE)
- missing = subprocess.check_output(['grep', '-v', 'tests'], stdin=p2.stdout)
+ p2 = subprocess.Popen(['xargs', 'egrep', '-n', '@since ?$'], stdin=p1.stdout, stdout=subprocess.PIPE)
+ missing = subprocess.check_output(['egrep', '-v', '/(tests|result)/'], stdin=p2.stdout)
content += "<tr><td>Empty @since:<br>\n<pre>%s</pre></td></tr>\n" % (missing)
except subprocess.CalledProcessError as e:
if e.returncode == 1:
@@ -33,13 +34,7 @@ except subprocess.CalledProcessError as e:
else:
raise e
-content += "<tr><td>Try demos<ul>"
-
-for demo in demos:
- content += "<li><a href='{url}/{demoName}-{version}'>{demoName}</a></li>\n".format(url=args.deployUrl, demoName=demo, version=args.version)
-
-content += """</ul></td></tr>
-<tr><td><a href="{url}">Build result page (See test results, pin and tag build and dependencies)</a></td></tr>
+content += """<tr><td><a href="{url}">Build result page (See test results, pin and tag build and dependencies)</a></td></tr>
</table>
</body>
</html>""".format(url=args.buildResultUrl)
diff --git a/scripts/GeneratePublishReport.py b/scripts/GeneratePublishReport.py
new file mode 100644
index 0000000000..6cd0791f24
--- /dev/null
+++ b/scripts/GeneratePublishReport.py
@@ -0,0 +1,65 @@
+#coding=UTF-8
+
+import argparse, cgi
+from os.path import exists, isdir
+from os import makedirs
+
+parser = argparse.ArgumentParser(description="Post-publish report generator")
+parser.add_argument("version", type=str, help="Vaadin version that was just built")
+parser.add_argument("buildResultUrl", type=str, help="URL for the build result page")
+
+args = parser.parse_args()
+
+resultPath = "result"
+if not exists(resultPath):
+ makedirs(resultPath)
+elif not isdir(resultPath):
+ print("Result path is not a directory.")
+ sys.exit(1)
+
+(major, minor, maintenance) = args.version.split(".", 2)
+prerelease = "." in maintenance
+if prerelease:
+ maintenance = maintenance.split('.')[0]
+
+content = """<html>
+<head></head>
+<body>
+<table>
+"""
+
+if not prerelease:
+ content += "<tr><td><a href='http://vaadin.com/download/release/{maj}.{min}/{ver}/'>Check {ver} is published to vaadin.com/download</td></tr>".format(maj=major, min=minor, ver=args.version)
+ content += "<tr><td><a href='http://repo1.maven.org/maven2/com/vaadin/vaadin-server/{ver}'>Check {ver} is published to maven.org (might take a while)</td></tr>".format(ver=args.version)
+else:
+ content += "<tr><td><a href='http://vaadin.com/download/prerelease/{maj}.{min}/{maj}.{min}.{main}/{ver}'>Check {ver} is published as prerelease to vaadin.com/download</td></tr>".format(maj=major, min=minor, main=maintenance, ver=args.version)
+ content += "<tr><td><a href='http://maven.vaadin.com/vaadin-prereleases/com/vaadin/vaadin-server/{ver}'>Check {ver} is published as prerelease to maven.vaadin.com</td></tr>".format(ver=args.version)
+
+
+content += """
+<tr><td>Verify Latest Vaadin 7: <iframe src="http://vaadin.com/download/LATEST7"></iframe></td></tr>
+<tr><td>Verify Vaadin 7 Version List: <iframe src="http://vaadin.com/download/VERSIONS_7"></iframe></td></tr>
+<tr><td>Verify Latest Vaadin 7.5: <iframe src="http://vaadin.com/download/release/7.5/LATEST"></iframe></td></tr>
+<tr><td>Verify Latest Vaadin 7.6: <iframe src="http://vaadin.com/download/release/7.6/LATEST"></iframe></td></tr>
+<tr><td>Verify Latest Vaadin 6: <iframe src="http://vaadin.com/download/LATEST"></iframe></td></tr>
+<tr><td>Verify Latest Vaadin 7 Prerelease: <iframe src="http://vaadin.com/download/PRERELEASES"></iframe></td></tr>"""
+
+if not prerelease:
+ content += '<tr><td><a href="https://dev.vaadin.com/admin/ticket/versions">Set latest version to default</a></td></tr>'
+
+content += """
+<tr><td><a href="http://test.vaadin.com/{version}/run/LabelModes?restartApplication">Verify uploaded to test.vaadin.com</a></td></tr>
+<tr><td><a href="https://github.com/vaadin/vaadin/tags">Verify tags pushed to GitHub</a></td></tr>""".format(version=args.version)
+
+if not prerelease:
+ content += '<tr><td><a href="http://vaadin.com/api">Verify API version list updated</a></td></tr>'
+
+content += """
+<tr><td><a href="https://dev.vaadin.com/query?status=pending-release&component=Core+Framework&resolution=fixed&milestone=Vaadin {version}&col=id&col=summary&col=component&col=milestone&col=status&col=type">Batch update tickets in Trac</a></td></tr>
+<tr><td><a href="{url}">Publish result page (See test results, pin and tag build and dependencies)</a></td></tr>
+</table>
+</body>
+</html>""".format(url=args.buildResultUrl, version=args.version)
+
+f = open("result/report.html", 'w')
+f.write(content)
diff --git a/scripts/GenerateStagingReport.py b/scripts/GenerateStagingReport.py
index fdcdc93fdb..23977aa933 100644
--- a/scripts/GenerateStagingReport.py
+++ b/scripts/GenerateStagingReport.py
@@ -1,6 +1,7 @@
#coding=UTF-8
from BuildArchetypes import archetypes, getDeploymentContext
+from BuildDemos import demos
import argparse, cgi
parser = argparse.ArgumentParser(description="Build report generator")
@@ -8,6 +9,7 @@ parser.add_argument("version", type=str, help="Vaadin version that was just buil
parser.add_argument("deployUrl", type=str, help="Base url of the deployment server")
parser.add_argument("buildResultUrl", type=str, help="URL for the build result page")
parser.add_argument("stagingRepo", type=str, help="URL for the staging repository")
+parser.add_argument("tbapiUrl", type=str, help="URL for the TestBench API build")
args = parser.parse_args()
@@ -17,7 +19,12 @@ content = """<html>
<table>
"""
-content += "<tr><td>Try archetype demos<ul>"
+content += "<tr><td>Try demos<ul>"
+
+for demo in demos:
+ content += "<li><a href='{url}/{demoName}-{version}'>{demoName}</a></li>\n".format(url=args.deployUrl, demoName=demo, version=args.version)
+
+content += "</ul></td></tr>\n<tr><td>Try archetype demos<ul>"
for archetype in archetypes:
content += "<li><a href='{url}/{context}'>{demo}</a></li>\n".format(url=args.deployUrl, demo=archetype, context=getDeploymentContext(archetype, args.version))
@@ -29,12 +36,48 @@ content += cgi.escape(""" <ibiblio name="vaadin-staging" usepoms="true" m2compat
root="{repoUrl}" />""".format(repoUrl=args.stagingRepo))
content += """</pre>
</td></tr>
-<tr><td><a href="https://dev.vaadin.com/milestone/Vaadin {version}">Trac Milestone</a></td></tr>
+<tr><td><a href="https://dev.vaadin.com/milestone/Vaadin {version}">Close Trac Milestone</a></td></tr>
+<tr><td><a href="https://dev.vaadin.com/query?status=pending-release&component=Core+Framework&resolution=fixed&col=id&col=summary&col=component&col=milestone&col=status&col=type">Verify pending release tickets still have milestone {version}</a></td></tr>
<tr><td><a href="https://dev.vaadin.com/admin/ticket/versions">Add version {version} to Trac</td></tr>
<tr><td><a href="{url}">Staging result page (See test results, pin and tag build and dependencies)</a></td></tr>
+<tr><td>Commands to tag all repositories (warning: do not run as a single script but set variables and check before any push commands - this has not been tested yet and the change IDs are missing)</td></tr>
+<tr><td><pre>
+VERSION={version}
+
+GERRIT_USER=[fill in your gerrit username]
+FRAMEWORK_REVISION=[fill in framework revision]
+SCREENSHOTS_REVISION=[fill in screenshot repository revision]
+ARCHETYPES_REVISION=[fill in maven-integration repository revision]
+PLUGIN_REVISION=[fill in maven plug-in repository revision]
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/vaadin
+cd vaadin
+git tag -a -m"$VERSION" $VERSION $FRAMEWORK_REVISION
+git push --tags
+cd ..
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/vaadin-screenshots
+cd vaadin-screenshots
+git tag -a -m"$VERSION" $VERSION $SCREENSHOTS_REVISION
+git push --tags
+cd ..
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/maven-integration
+cd maven-integration
+git tag -a -m"$VERSION" $VERSION $ARCHETYPES_REVISION
+git push --tags
+cd ..
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/maven-plugin
+cd maven-plugin
+git tag -a -m"$VERSION" $VERSION $PLUGIN_REVISION
+git push --tags
+cd ..
+</pre></td></tr>
+<tr><td><a href="{tbapi}">Build and publish TestBench API for version {version} if proceeding</a></td></tr>
</table>
</body>
-</html>""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version)
+</html>""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version, tbapi=args.tbapiUrl)
f = open("result/report.html", 'w')
f.write(content)
diff --git a/server/build.xml b/server/build.xml
index 4bb2bde730..95c0b0add4 100644
--- a/server/build.xml
+++ b/server/build.xml
@@ -34,7 +34,7 @@
</target>
<target name="jar" depends="compress-files">
<property name="server.osgi.import"
- value="javax.servlet;version=&quot;2.4.0&quot;,javax.servlet.http;version=&quot;2.4.0&quot;,javax.validation;version=&quot;1.0.0.GA&quot;;resolution:=optional,org.jsoup;version=&quot;1.6.3&quot;,org.jsoup.parser;version=&quot;1.6.3&quot;,org.jsoup.nodes;version=&quot;1.6.3&quot;,org.jsoup.helper;version=&quot;1.6.3&quot;,org.jsoup.safety;version=&quot;1.6.3&quot;,org.jsoup.select;version=&quot;1.6.3&quot;" />
+ value="javax.servlet;version=&quot;2.4.0&quot;,javax.servlet.http;version=&quot;2.4.0&quot;,javax.validation;version=&quot;1.0.0.GA&quot;;resolution:=optional,org.jsoup;version=&quot;1.6.3&quot;,org.jsoup.parser;version=&quot;1.6.3&quot;,org.jsoup.nodes;version=&quot;1.6.3&quot;,org.jsoup.helper;version=&quot;1.6.3&quot;,org.jsoup.safety;version=&quot;1.6.3&quot;,org.jsoup.select;version=&quot;1.6.3&quot;,javax.portlet;version=&quot;[2.0,3)&quot;;resolution:=optional,javax.portlet.filter;version=&quot;[2.0,3)&quot;;resolution:=optional,com.liferay.portal.kernel.util;resolution:=optional" />
<property name="server.osgi.require"
value="com.google.gwt.thirdparty.guava;bundle-version=&quot;16.0.1.vaadin1&quot;,com.vaadin.shared;bundle-version=&quot;${vaadin.version}&quot;,com.vaadin.push;bundle-version=&quot;${vaadin.version}&quot;;resolution:=optional,com.vaadin.sass-compiler;bundle-version=&quot;${vaadin.sass.version}&quot;;resolution:=optional" />
<antcall target="common.jar">
diff --git a/server/ivy.xml b/server/ivy.xml
index e9bc8b818d..0711b4b2ea 100644
--- a/server/ivy.xml
+++ b/server/ivy.xml
@@ -36,7 +36,7 @@
<!-- Google App Engine -->
<dependency org="com.google.appengine" name="appengine-api-1.0-sdk"
- rev="1.2.1" conf="build-provided,ide,test -> default" />
+ rev="1.7.7" conf="build-provided,ide,test -> default" />
<!-- Bean Validation API -->
<dependency org="javax.validation" name="validation-api"
diff --git a/server/src/com/vaadin/data/DataGenerator.java b/server/src/com/vaadin/data/DataGenerator.java
new file mode 100644
index 0000000000..a5333b8523
--- /dev/null
+++ b/server/src/com/vaadin/data/DataGenerator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.data;
+
+import java.io.Serializable;
+
+import com.vaadin.ui.Grid.AbstractGridExtension;
+import com.vaadin.ui.Grid.AbstractRenderer;
+
+import elemental.json.JsonObject;
+
+/**
+ * Interface for {@link AbstractGridExtension}s that allows adding data to row
+ * objects being sent to client by the {@link RpcDataProviderExtension}.
+ * <p>
+ * {@link AbstractRenderer} implements this interface to provide encoded data to
+ * client for {@link Renderer}s automatically.
+ *
+ * @since 7.6
+ * @author Vaadin Ltd
+ */
+public interface DataGenerator extends Serializable {
+
+ /**
+ * Adds data to row object for given item and item id being sent to client.
+ *
+ * @param itemId
+ * item id of item
+ * @param item
+ * item being sent to client
+ * @param rowData
+ * row object being sent to client
+ */
+ public void generateData(Object itemId, Item item, JsonObject rowData);
+
+}
diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java
index b3c7972b52..78c87ab23d 100644
--- a/server/src/com/vaadin/data/RpcDataProviderExtension.java
+++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java
@@ -23,14 +23,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Set;
-import java.util.logging.Logger;
-import com.google.gwt.thirdparty.guava.common.collect.BiMap;
-import com.google.gwt.thirdparty.guava.common.collect.HashBiMap;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
@@ -43,31 +38,23 @@ import com.vaadin.data.Container.ItemSetChangeNotifier;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.Property.ValueChangeNotifier;
-import com.vaadin.data.util.converter.Converter;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.KeyMapper;
import com.vaadin.shared.data.DataProviderRpc;
import com.vaadin.shared.data.DataRequestRpc;
-import com.vaadin.shared.ui.grid.DetailsConnectorChange;
import com.vaadin.shared.ui.grid.GridClientRpc;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.shared.ui.grid.Range;
-import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.Component;
import com.vaadin.ui.Grid;
-import com.vaadin.ui.Grid.CellReference;
-import com.vaadin.ui.Grid.CellStyleGenerator;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.Grid.DetailsGenerator;
import com.vaadin.ui.Grid.RowReference;
-import com.vaadin.ui.Grid.RowStyleGenerator;
-import com.vaadin.ui.renderers.Renderer;
import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;
-import elemental.json.JsonValue;
/**
* Provides Vaadin server-side container data source to a
@@ -82,445 +69,84 @@ import elemental.json.JsonValue;
public class RpcDataProviderExtension extends AbstractExtension {
/**
- * ItemId to Key to ItemId mapper.
- * <p>
- * This class is used when transmitting information about items in container
- * related to Grid. It introduces a consistent way of mapping ItemIds and
- * its container to a String that can be mapped back to ItemId.
- * <p>
- * <em>Technical note:</em> This class also keeps tabs on which indices are
- * being shown/selected, and is able to clean up after itself once the
- * itemId &lrarr; key mapping is not needed anymore. In other words, this
- * doesn't leak memory.
+ * Class for keeping track of current items and ValueChangeListeners.
+ *
+ * @since 7.6
*/
- public class DataProviderKeyMapper implements Serializable {
- private final BiMap<Object, String> itemIdToKey = HashBiMap.create();
- private Set<Object> pinnedItemIds = new HashSet<Object>();
- private long rollingIndex = 0;
-
- private DataProviderKeyMapper() {
- // private implementation
- }
-
- /**
- * Sets the currently active rows. This will purge any unpinned rows
- * from cache.
- *
- * @param itemIds
- * collection of itemIds to map to row keys
- */
- void setActiveRows(Collection<?> itemIds) {
- Set<Object> itemSet = new HashSet<Object>(itemIds);
- Set<Object> itemsRemoved = new HashSet<Object>();
- for (Object itemId : itemIdToKey.keySet()) {
- if (!itemSet.contains(itemId) && !isPinned(itemId)) {
- itemsRemoved.add(itemId);
- }
- }
-
- for (Object itemId : itemsRemoved) {
- detailComponentManager.destroyDetails(itemId);
- itemIdToKey.remove(itemId);
- }
-
- for (Object itemId : itemSet) {
- itemIdToKey.put(itemId, getKey(itemId));
- if (visibleDetails.contains(itemId)) {
- detailComponentManager.createDetails(itemId,
- indexOf(itemId));
- }
- }
- }
-
- private String nextKey() {
- return String.valueOf(rollingIndex++);
- }
+ private class ActiveItemHandler implements Serializable, DataGenerator {
- /**
- * Gets the key for a given item id. Creates a new key mapping if no
- * existing mapping was found for the given item id.
- *
- * @since 7.5.0
- * @param itemId
- * the item id to get the key for
- * @return the key for the given item id
- */
- public String getKey(Object itemId) {
- String key = itemIdToKey.get(itemId);
- if (key == null) {
- key = nextKey();
- itemIdToKey.put(itemId, key);
- }
- return key;
- }
+ private final Map<Object, GridValueChangeListener> activeItemMap = new HashMap<Object, GridValueChangeListener>();
+ private final KeyMapper<Object> keyMapper = new KeyMapper<Object>();
+ private final Set<Object> droppedItems = new HashSet<Object>();
/**
- * Gets keys for a collection of item ids.
+ * Registers ValueChangeListeners for given item ids.
* <p>
- * If the itemIds are currently cached, the existing keys will be used.
- * Otherwise new ones will be created.
+ * Note: This method will clean up any unneeded listeners and key
+ * mappings
*
* @param itemIds
- * the item ids for which to get keys
- * @return keys for the {@code itemIds}
+ * collection of new active item ids
*/
- public List<String> getKeys(Collection<Object> itemIds) {
- if (itemIds == null) {
- throw new IllegalArgumentException("itemIds can't be null");
- }
-
- ArrayList<String> keys = new ArrayList<String>(itemIds.size());
+ public void addActiveItems(Collection<?> itemIds) {
for (Object itemId : itemIds) {
- keys.add(getKey(itemId));
- }
- return keys;
- }
-
- /**
- * Gets the registered item id based on its key.
- * <p>
- * A key is used to identify a particular row on both a server and a
- * client. This method can be used to get the item id for the row key
- * that the client has sent.
- *
- * @param key
- * the row key for which to retrieve an item id
- * @return the item id corresponding to {@code key}
- * @throws IllegalStateException
- * if the key mapper does not have a record of {@code key} .
- */
- public Object getItemId(String key) throws IllegalStateException {
- Object itemId = itemIdToKey.inverse().get(key);
- if (itemId != null) {
- return itemId;
- } else {
- throw new IllegalStateException("No item id for key " + key
- + " found.");
- }
- }
-
- /**
- * Gets corresponding item ids for each of the keys in a collection.
- *
- * @param keys
- * the keys for which to retrieve item ids
- * @return a collection of item ids for the {@code keys}
- * @throws IllegalStateException
- * if one or more of keys don't have a corresponding item id
- * in the cache
- */
- public Collection<Object> getItemIds(Collection<String> keys)
- throws IllegalStateException {
- if (keys == null) {
- throw new IllegalArgumentException("keys may not be null");
- }
-
- ArrayList<Object> itemIds = new ArrayList<Object>(keys.size());
- for (String key : keys) {
- itemIds.add(getItemId(key));
- }
- return itemIds;
- }
-
- /**
- * Pin an item id to be cached indefinitely.
- * <p>
- * Normally when an itemId is not an active row, it is discarded from
- * the cache. Pinning an item id will make sure that it is kept in the
- * cache.
- * <p>
- * In effect, while an item id is pinned, it always has the same key.
- *
- * @param itemId
- * the item id to pin
- * @throws IllegalStateException
- * if {@code itemId} was already pinned
- * @see #unpin(Object)
- * @see #isPinned(Object)
- * @see #getItemIds(Collection)
- */
- public void pin(Object itemId) throws IllegalStateException {
- if (isPinned(itemId)) {
- throw new IllegalStateException("Item id " + itemId
- + " was pinned already");
- }
- pinnedItemIds.add(itemId);
- }
-
- /**
- * Unpin an item id.
- * <p>
- * This cancels the effect of pinning an item id. If the item id is
- * currently inactive, it will be immediately removed from the cache.
- *
- * @param itemId
- * the item id to unpin
- * @throws IllegalStateException
- * if {@code itemId} was not pinned
- * @see #pin(Object)
- * @see #isPinned(Object)
- * @see #getItemIds(Collection)
- */
- public void unpin(Object itemId) throws IllegalStateException {
- if (!isPinned(itemId)) {
- throw new IllegalStateException("Item id " + itemId
- + " was not pinned");
+ if (!activeItemMap.containsKey(itemId)) {
+ activeItemMap.put(itemId, new GridValueChangeListener(
+ itemId, container.getItem(itemId)));
+ }
}
- pinnedItemIds.remove(itemId);
+ // Remove still active rows that were "dropped"
+ droppedItems.removeAll(itemIds);
+ internalDropActiveItems(droppedItems);
+ droppedItems.clear();
}
/**
- * Checks whether an item id is pinned or not.
+ * Marks given item id as dropped. Dropped items are cleared when adding
+ * new active items.
*
* @param itemId
- * the item id to check for pin status
- * @return {@code true} iff the item id is currently pinned
- */
- public boolean isPinned(Object itemId) {
- return pinnedItemIds.contains(itemId);
- }
- }
-
- /**
- * A helper class that handles the client-side Escalator logic relating to
- * making sure that whatever is currently visible to the user, is properly
- * initialized and otherwise handled on the server side (as far as
- * required).
- * <p>
- * This bookeeping includes, but is not limited to:
- * <ul>
- * <li>listening to the currently visible {@link com.vaadin.data.Property
- * Properties'} value changes on the server side and sending those back to
- * the client; and
- * <li>attaching and detaching {@link com.vaadin.ui.Component Components}
- * from the Vaadin Component hierarchy.
- * </ul>
- */
- private class ActiveRowHandler implements Serializable {
- /**
- * A map from index to the value change listener used for all of column
- * properties
- */
- private final Map<Integer, GridValueChangeListener> valueChangeListeners = new HashMap<Integer, GridValueChangeListener>();
-
- /**
- * The currently active range. Practically, it's the range of row
- * indices being cached currently.
- */
- private Range activeRange = Range.withLength(0, 0);
-
- /**
- * A hook for making sure that appropriate data is "active". All other
- * rows should be "inactive".
- * <p>
- * "Active" can mean different things in different contexts. For
- * example, only the Properties in the active range need
- * ValueChangeListeners. Also, whenever a row with a Component becomes
- * active, it needs to be attached (and conversely, when inactive, it
- * needs to be detached).
- *
- * @param firstActiveRow
- * the first active row
- * @param activeRowCount
- * the number of active rows
- */
- public void setActiveRows(Range newActiveRange) {
-
- // TODO [[Components]] attach and detach components
-
- /*-
- * Example
- *
- * New Range: [3, 4, 5, 6, 7]
- * Old Range: [1, 2, 3, 4, 5]
- * Result: [1, 2][3, 4, 5] []
- */
- final Range[] depractionPartition = activeRange
- .partitionWith(newActiveRange);
- removeValueChangeListeners(depractionPartition[0]);
- removeValueChangeListeners(depractionPartition[2]);
-
- /*-
- * Example
- *
- * Old Range: [1, 2, 3, 4, 5]
- * New Range: [3, 4, 5, 6, 7]
- * Result: [] [3, 4, 5][6, 7]
- */
- final Range[] activationPartition = newActiveRange
- .partitionWith(activeRange);
- addValueChangeListeners(activationPartition[0]);
- addValueChangeListeners(activationPartition[2]);
-
- activeRange = newActiveRange;
-
- assert valueChangeListeners.size() == newActiveRange.length() : "Value change listeners not set up correctly!";
- }
-
- private void addValueChangeListeners(Range range) {
- for (Integer i = range.getStart(); i < range.getEnd(); i++) {
-
- final Object itemId = container.getIdByIndex(i);
- final Item item = container.getItem(itemId);
-
- assert valueChangeListeners.get(i) == null : "Overwriting existing listener";
-
- GridValueChangeListener listener = new GridValueChangeListener(
- itemId, item);
- valueChangeListeners.put(i, listener);
- }
- }
-
- private void removeValueChangeListeners(Range range) {
- for (Integer i = range.getStart(); i < range.getEnd(); i++) {
- final GridValueChangeListener listener = valueChangeListeners
- .remove(i);
-
- assert listener != null : "Trying to remove nonexisting listener";
-
- listener.removeListener();
- }
- }
-
- /**
- * Manages removed columns in active rows.
- * <p>
- * This method does <em>not</em> send data again to the client.
- *
- * @param removedColumns
- * the columns that have been removed from the grid
+ * dropped item id
*/
- public void columnsRemoved(Collection<Column> removedColumns) {
- if (removedColumns.isEmpty()) {
- return;
- }
-
- for (GridValueChangeListener listener : valueChangeListeners
- .values()) {
- listener.removeColumns(removedColumns);
+ public void dropActiveItem(Object itemId) {
+ if (activeItemMap.containsKey(itemId)) {
+ droppedItems.add(itemId);
}
}
- /**
- * Manages added columns in active rows.
- * <p>
- * This method sends the data for the changed rows to client side.
- *
- * @param addedColumns
- * the columns that have been added to the grid
- */
- public void columnsAdded(Collection<Column> addedColumns) {
- if (addedColumns.isEmpty()) {
- return;
- }
+ private void internalDropActiveItems(Collection<Object> itemIds) {
+ for (Object itemId : droppedItems) {
+ assert activeItemMap.containsKey(itemId) : "Item ID should exist in the activeItemMap";
- for (GridValueChangeListener listener : valueChangeListeners
- .values()) {
- listener.addColumns(addedColumns);
+ activeItemMap.remove(itemId).removeListener();
+ keyMapper.remove(itemId);
}
}
/**
- * Handles the insertion of rows.
- * <p>
- * This method's responsibilities are to:
- * <ul>
- * <li>shift the internal bookkeeping by <code>count</code> if the
- * insertion happens above currently active range
- * <li>ignore rows inserted below the currently active range
- * <li>shift (and deactivate) rows pushed out of view
- * <li>activate rows that are inserted in the current viewport
- * </ul>
+ * Gets a collection copy of currently active item ids.
*
- * @param firstIndex
- * the index of the first inserted rows
- * @param count
- * the number of rows inserted at <code>firstIndex</code>
+ * @return collection of item ids
*/
- public void insertRows(int firstIndex, int count) {
- if (firstIndex < activeRange.getStart()) {
- moveListeners(activeRange, count);
- activeRange = activeRange.offsetBy(count);
- } else if (firstIndex < activeRange.getEnd()) {
- int end = activeRange.getEnd();
- // Move rows from first added index by count
- Range movedRange = Range.between(firstIndex, end);
- moveListeners(movedRange, count);
- // Remove excess listeners from extra rows
- removeValueChangeListeners(Range.withLength(end, count));
- // Add listeners for new rows
- final Range freshRange = Range.withLength(firstIndex, count);
- addValueChangeListeners(freshRange);
- } else {
- // out of view, noop
- }
+ public Collection<Object> getActiveItemIds() {
+ return new HashSet<Object>(activeItemMap.keySet());
}
/**
- * Handles the removal of rows.
- * <p>
- * This method's responsibilities are to:
- * <ul>
- * <li>shift the internal bookkeeping by <code>count</code> if the
- * removal happens above currently active range
- * <li>ignore rows removed below the currently active range
- * </ul>
+ * Gets a collection copy of currently active ValueChangeListeners.
*
- * @param firstIndex
- * the index of the first removed rows
- * @param count
- * the number of rows removed at <code>firstIndex</code>
+ * @return collection of value change listeners
*/
- public void removeRows(int firstIndex, int count) {
- Range removed = Range.withLength(firstIndex, count);
- if (removed.intersects(activeRange)) {
- final Range[] deprecated = activeRange.partitionWith(removed);
- // Remove the listeners that are no longer existing
- removeValueChangeListeners(deprecated[1]);
-
- // Move remaining listeners to fill the listener map correctly
- moveListeners(deprecated[2], -deprecated[1].length());
- activeRange = Range.withLength(activeRange.getStart(),
- activeRange.length() - deprecated[1].length());
-
- } else {
- if (removed.getEnd() < activeRange.getStart()) {
- /* firstIndex < lastIndex < start */
- moveListeners(activeRange, -count);
- activeRange = activeRange.offsetBy(-count);
- }
- /* else: end <= firstIndex, no need to do anything */
- }
+ public Collection<GridValueChangeListener> getValueChangeListeners() {
+ return new HashSet<GridValueChangeListener>(activeItemMap.values());
}
- /**
- * Moves value change listeners in map with given index range by count
- */
- private void moveListeners(Range movedRange, int diff) {
- if (diff < 0) {
- for (Integer i = movedRange.getStart(); i < movedRange.getEnd(); ++i) {
- moveListener(i, i + diff);
- }
- } else if (diff > 0) {
- for (Integer i = movedRange.getEnd() - 1; i >= movedRange
- .getStart(); --i) {
- moveListener(i, i + diff);
- }
- } else {
- // diff == 0 should not happen. If it does, should be no-op
- return;
- }
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ rowData.put(GridState.JSONKEY_ROWKEY, keyMapper.key(itemId));
}
- private void moveListener(Integer oldIndex, Integer newIndex) {
- assert valueChangeListeners.get(newIndex) == null : "Overwriting existing listener";
-
- GridValueChangeListener listener = valueChangeListeners
- .remove(oldIndex);
- assert listener != null : "Moving nonexisting listener.";
- valueChangeListeners.put(newIndex, listener);
- }
}
/**
@@ -601,7 +227,8 @@ public class RpcDataProviderExtension extends AbstractExtension {
* @since 7.5.0
* @author Vaadin Ltd
*/
- public static final class DetailComponentManager implements Serializable {
+ // TODO this should probably be a static nested class
+ public final class DetailComponentManager implements DataGenerator {
/**
* This map represents all the components that have been requested for
* each item id.
@@ -609,9 +236,8 @@ public class RpcDataProviderExtension extends AbstractExtension {
* Normally this map is consistent with what is displayed in the
* component hierarchy (and thus the DOM). The only time this map is out
* of sync with the DOM is between the any calls to
- * {@link #createDetails(Object, int)} or
- * {@link #destroyDetails(Object)}, and
- * {@link GridClientRpc#setDetailsConnectorChanges(Set)}.
+ * {@link #createDetails(Object)} or {@link #destroyDetails(Object)},
+ * and {@link GridClientRpc#setDetailsConnectorChanges(Set)}.
* <p>
* This is easily checked: if {@link #unattachedComponents} is
* {@link Collection#isEmpty() empty}, then this field is consistent
@@ -620,34 +246,11 @@ public class RpcDataProviderExtension extends AbstractExtension {
private final Map<Object, Component> visibleDetailsComponents = Maps
.newHashMap();
- /** A lookup map for which row contains which details component. */
- private BiMap<Integer, Component> rowIndexToDetails = HashBiMap
- .create();
-
- /**
- * A copy of {@link #rowIndexToDetails} from its last stable state. Used
- * for creating a diff against {@link #rowIndexToDetails}.
- *
- * @see #getAndResetConnectorChanges()
- */
- private BiMap<Integer, Component> prevRowIndexToDetails = HashBiMap
- .create();
-
- /**
- * A set keeping track on components that have been created, but not
- * attached. They should be attached at some later point in time.
- * <p>
- * This isn't strictly requried, but it's a handy explicit log. You
- * could find out the same thing by taking out all the other components
- * and checking whether Grid is their parent or not.
- */
- private final Set<Component> unattachedComponents = Sets.newHashSet();
-
/**
* Keeps tabs on all the details that did not get a component during
- * {@link #createDetails(Object, int)}.
+ * {@link #createDetails(Object)}.
*/
- private final Map<Object, Integer> emptyDetails = Maps.newHashMap();
+ private final Set<Object> emptyDetails = Sets.newHashSet();
private Grid grid;
@@ -661,19 +264,16 @@ public class RpcDataProviderExtension extends AbstractExtension {
* the item id for which to create the details component.
* Assumed not <code>null</code> and that a component is not
* currently present for this item previously
- * @param rowIndex
- * the row index for {@code itemId}
* @throws IllegalStateException
* if the current details generator provides a component
* that was manually attached, or if the same instance has
* already been provided
*/
- public void createDetails(Object itemId, int rowIndex)
- throws IllegalStateException {
+ public void createDetails(Object itemId) throws IllegalStateException {
assert itemId != null : "itemId was null";
- Integer newRowIndex = Integer.valueOf(rowIndex);
- if (visibleDetailsComponents.containsKey(itemId)) {
+ if (visibleDetailsComponents.containsKey(itemId)
+ || emptyDetails.contains(itemId)) {
// Don't overwrite existing components
return;
}
@@ -684,58 +284,26 @@ public class RpcDataProviderExtension extends AbstractExtension {
DetailsGenerator detailsGenerator = grid.getDetailsGenerator();
Component details = detailsGenerator.getDetails(rowReference);
if (details != null) {
- String generatorName = detailsGenerator.getClass().getName();
if (details.getParent() != null) {
- throw new IllegalStateException(generatorName
+ String name = detailsGenerator.getClass().getName();
+ throw new IllegalStateException(name
+ " generated a details component that already "
- + "was attached. (itemId: " + itemId + ", row: "
- + rowIndex + ", component: " + details);
- }
-
- if (rowIndexToDetails.containsValue(details)) {
- throw new IllegalStateException(generatorName
- + " provided a details component that already "
- + "exists in Grid. (itemId: " + itemId + ", row: "
- + rowIndex + ", component: " + details);
+ + "was attached. (itemId: " + itemId
+ + ", component: " + details + ")");
}
visibleDetailsComponents.put(itemId, details);
- rowIndexToDetails.put(newRowIndex, details);
- unattachedComponents.add(details);
- assert !emptyDetails.containsKey(itemId) : "Bookeeping thinks "
+ details.setParent(grid);
+ grid.markAsDirty();
+
+ assert !emptyDetails.contains(itemId) : "Bookeeping thinks "
+ "itemId is empty even though we just created a "
+ "component for it (" + itemId + ")";
} else {
- assert assertItemIdHasNotMovedAndNothingIsOverwritten(itemId,
- newRowIndex);
- emptyDetails.put(itemId, newRowIndex);
- }
-
- /*
- * Don't attach the components here. It's done by
- * GridServerRpc.sendDetailsComponents in a separate roundtrip.
- */
- }
-
- private boolean assertItemIdHasNotMovedAndNothingIsOverwritten(
- Object itemId, Integer newRowIndex) {
-
- Integer oldRowIndex = emptyDetails.get(itemId);
- if (!SharedUtil.equals(oldRowIndex, newRowIndex)) {
-
- assert !emptyDetails.containsKey(itemId) : "Unexpected "
- + "change of empty details row index for itemId "
- + itemId + " from " + oldRowIndex + " to "
- + newRowIndex;
-
- assert !emptyDetails.containsValue(newRowIndex) : "Bookkeeping"
- + " already had another itemId for this empty index "
- + "(index: " + newRowIndex + ", new itemId: " + itemId
- + ")";
+ emptyDetails.add(itemId);
}
- return true;
}
/**
@@ -756,8 +324,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
return;
}
- rowIndexToDetails.inverse().remove(removedComponent);
-
removedComponent.setParent(null);
grid.markAsDirty();
}
@@ -773,81 +339,12 @@ public class RpcDataProviderExtension extends AbstractExtension {
public Collection<Component> getComponents() {
Set<Component> components = new HashSet<Component>(
visibleDetailsComponents.values());
- components.removeAll(unattachedComponents);
return components;
}
- /**
- * Gets information on how the connectors have changed.
- * <p>
- * This method only returns the changes that have been made between two
- * calls of this method. I.e. Calling this method once will reset the
- * state for the next state.
- * <p>
- * Used internally by the Grid object.
- *
- * @return information on how the connectors have changed
- */
- public Set<DetailsConnectorChange> getAndResetConnectorChanges() {
- Set<DetailsConnectorChange> changes = new HashSet<DetailsConnectorChange>();
-
- // populate diff with added/changed
- for (Entry<Integer, Component> entry : rowIndexToDetails.entrySet()) {
- Component component = entry.getValue();
- assert component != null : "rowIndexToDetails contains a null component";
-
- Integer newIndex = entry.getKey();
- Integer oldIndex = prevRowIndexToDetails.inverse().get(
- component);
-
- /*
- * only attach components. Detaching already happened in
- * destroyDetails.
- */
- if (newIndex != null && oldIndex == null) {
- assert unattachedComponents.contains(component) : "unattachedComponents does not contain component for index "
- + newIndex + " (" + component + ")";
- component.setParent(grid);
- unattachedComponents.remove(component);
- }
-
- if (!SharedUtil.equals(oldIndex, newIndex)) {
- changes.add(new DetailsConnectorChange(component, oldIndex,
- newIndex, emptyDetails.containsKey(component)));
- }
- }
-
- // populate diff with removed
- for (Entry<Integer, Component> entry : prevRowIndexToDetails
- .entrySet()) {
- Integer oldIndex = entry.getKey();
- Component component = entry.getValue();
- Integer newIndex = rowIndexToDetails.inverse().get(component);
- if (newIndex == null) {
- changes.add(new DetailsConnectorChange(null, oldIndex,
- null, emptyDetails.containsValue(oldIndex)));
- }
- }
-
- // reset diff map
- prevRowIndexToDetails = HashBiMap.create(rowIndexToDetails);
-
- return changes;
- }
-
public void refresh(Object itemId) {
- Component component = visibleDetailsComponents.get(itemId);
- Integer rowIndex = null;
- if (component != null) {
- rowIndex = rowIndexToDetails.inverse().get(component);
- destroyDetails(itemId);
- } else {
- rowIndex = emptyDetails.remove(itemId);
- }
-
- assert rowIndex != null : "Given itemId does not map to an "
- + "existing detail row (" + itemId + ")";
- createDetails(itemId, rowIndex.intValue());
+ destroyDetails(itemId);
+ createDetails(itemId);
}
void setGrid(Grid grid) {
@@ -856,12 +353,29 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
this.grid = grid;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 7.6
+ */
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ if (visibleDetails.contains(itemId)) {
+ // Double check to be sure details component exists.
+ detailComponentManager.createDetails(itemId);
+ Component detailsComponent = visibleDetailsComponents
+ .get(itemId);
+ rowData.put(
+ GridState.JSONKEY_DETAILS_VISIBLE,
+ (detailsComponent != null ? detailsComponent
+ .getConnectorId() : ""));
+ }
+ }
}
private final Indexed container;
- private final ActiveRowHandler activeRowHandler = new ActiveRowHandler();
-
private DataProviderRpc rpc;
private final ItemSetChangeListener itemListener = new ItemSetChangeListener() {
@@ -922,22 +436,10 @@ public class RpcDataProviderExtension extends AbstractExtension {
* taking all the corner cases into account.
*/
- Map<Integer, GridValueChangeListener> listeners = activeRowHandler.valueChangeListeners;
- for (GridValueChangeListener listener : listeners.values()) {
- listener.removeListener();
- }
-
- // Wipe clean all details.
- HashSet<Object> detailItemIds = new HashSet<Object>(
- detailComponentManager.visibleDetailsComponents
- .keySet());
- for (Object itemId : detailItemIds) {
+ for (Object itemId : visibleDetails) {
detailComponentManager.destroyDetails(itemId);
}
- listeners.clear();
- activeRowHandler.activeRange = Range.withLength(0, 0);
-
/* Mark as dirty to push changes in beforeClientResponse */
bareItemSetTriggeredSizeChange = true;
markAsDirty();
@@ -945,16 +447,9 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
};
- private final DataProviderKeyMapper keyMapper = new DataProviderKeyMapper();
-
- private KeyMapper<Object> columnKeys;
-
/** RpcDataProvider should send the current cache again. */
private boolean refreshCache = false;
- private RowReference rowReference;
- private CellReference cellReference;
-
/** Set of updated item ids */
private Set<Object> updatedItemIds = new LinkedHashSet<Object>();
@@ -971,10 +466,15 @@ public class RpcDataProviderExtension extends AbstractExtension {
* This map represents all the details that are user-defined as visible.
* This does not reflect the status in the DOM.
*/
- private Set<Object> visibleDetails = new HashSet<Object>();
+ // TODO this should probably be inside DetailComponentManager
+ private final Set<Object> visibleDetails = new HashSet<Object>();
private final DetailComponentManager detailComponentManager = new DetailComponentManager();
+ private final Set<DataGenerator> dataGenerators = new LinkedHashSet<DataGenerator>();
+
+ private final ActiveItemHandler activeItemHandler = new ActiveItemHandler();
+
/**
* Creates a new data provider using the given container.
*
@@ -989,22 +489,15 @@ public class RpcDataProviderExtension extends AbstractExtension {
@Override
public void requestRows(int firstRow, int numberOfRows,
int firstCachedRowIndex, int cacheSize) {
-
pushRowData(firstRow, numberOfRows, firstCachedRowIndex,
cacheSize);
}
@Override
- public void setPinned(String key, boolean isPinned) {
- Object itemId = keyMapper.getItemId(key);
- if (isPinned) {
- // Row might already be pinned if it was selected from the
- // server
- if (!keyMapper.isPinned(itemId)) {
- keyMapper.pin(itemId);
- }
- } else {
- keyMapper.unpin(itemId);
+ public void dropRows(JsonArray rowKeys) {
+ for (int i = 0; i < rowKeys.length(); ++i) {
+ activeItemHandler.dropActiveItem(getKeyMapper().get(
+ rowKeys.getString(i)));
}
}
});
@@ -1014,6 +507,8 @@ public class RpcDataProviderExtension extends AbstractExtension {
.addItemSetChangeListener(itemListener);
}
+ addDataGenerator(activeItemHandler);
+ addDataGenerator(detailComponentManager);
}
/**
@@ -1045,16 +540,11 @@ public class RpcDataProviderExtension extends AbstractExtension {
// Send current rows again if needed.
if (refreshCache) {
- int firstRow = activeRowHandler.activeRange.getStart();
- int numberOfRows = activeRowHandler.activeRange.length();
-
- pushRowData(firstRow, numberOfRows, firstRow, numberOfRows);
+ updatedItemIds.addAll(activeItemHandler.getActiveItemIds());
}
}
- for (Object itemId : updatedItemIds) {
- internalUpdateRowData(itemId);
- }
+ internalUpdateRows(updatedItemIds);
// Clear all changes.
rowChanges.clear();
@@ -1076,7 +566,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
List<?> itemIds = container.getItemIds(fullRange.getStart(),
fullRange.length());
- keyMapper.setActiveRows(itemIds);
JsonArray rows = Json.createArray();
@@ -1088,83 +577,25 @@ public class RpcDataProviderExtension extends AbstractExtension {
for (int i = 0; i < newRange.length() && i + diff < itemIds.size(); ++i) {
Object itemId = itemIds.get(i + diff);
+
rows.set(i, getRowData(getGrid().getColumns(), itemId));
}
rpc.setRowData(firstRowToPush, rows);
- activeRowHandler.setActiveRows(fullRange);
+ activeItemHandler.addActiveItems(itemIds);
}
- private JsonValue getRowData(Collection<Column> columns, Object itemId) {
+ private JsonObject getRowData(Collection<Column> columns, Object itemId) {
Item item = container.getItem(itemId);
- JsonObject rowData = Json.createObject();
-
- Grid grid = getGrid();
-
- for (Column column : columns) {
- Object propertyId = column.getPropertyId();
-
- Object propertyValue = item.getItemProperty(propertyId).getValue();
- JsonValue encodedValue = encodeValue(propertyValue,
- column.getRenderer(), column.getConverter(),
- grid.getLocale());
-
- rowData.put(columnKeys.key(propertyId), encodedValue);
- }
-
final JsonObject rowObject = Json.createObject();
- rowObject.put(GridState.JSONKEY_DATA, rowData);
- rowObject.put(GridState.JSONKEY_ROWKEY, keyMapper.getKey(itemId));
-
- if (visibleDetails.contains(itemId)) {
- rowObject.put(GridState.JSONKEY_DETAILS_VISIBLE, true);
- }
-
- rowReference.set(itemId);
-
- CellStyleGenerator cellStyleGenerator = grid.getCellStyleGenerator();
- if (cellStyleGenerator != null) {
- setGeneratedCellStyles(cellStyleGenerator, rowObject, columns);
- }
- RowStyleGenerator rowStyleGenerator = grid.getRowStyleGenerator();
- if (rowStyleGenerator != null) {
- setGeneratedRowStyles(rowStyleGenerator, rowObject);
+ for (DataGenerator dg : dataGenerators) {
+ dg.generateData(itemId, item, rowObject);
}
return rowObject;
}
- private void setGeneratedCellStyles(CellStyleGenerator generator,
- JsonObject rowObject, Collection<Column> columns) {
- JsonObject cellStyles = null;
- for (Column column : columns) {
- Object propertyId = column.getPropertyId();
- cellReference.set(propertyId);
- String style = generator.getStyle(cellReference);
- if (style != null && !style.isEmpty()) {
- if (cellStyles == null) {
- cellStyles = Json.createObject();
- }
-
- String columnKey = columnKeys.key(propertyId);
- cellStyles.put(columnKey, style);
- }
- }
- if (cellStyles != null) {
- rowObject.put(GridState.JSONKEY_CELLSTYLES, cellStyles);
- }
-
- }
-
- private void setGeneratedRowStyles(RowStyleGenerator generator,
- JsonObject rowObject) {
- String rowStyle = generator.getStyle(rowReference);
- if (rowStyle != null && !rowStyle.isEmpty()) {
- rowObject.put(GridState.JSONKEY_ROWSTYLE, rowStyle);
- }
- }
-
/**
* Makes the data source available to the given {@link Grid} component.
*
@@ -1173,13 +604,38 @@ public class RpcDataProviderExtension extends AbstractExtension {
* @param columnKeys
* the key mapper for columns
*/
- public void extend(Grid component, KeyMapper<Object> columnKeys) {
- this.columnKeys = columnKeys;
+ public void extend(Grid component) {
detailComponentManager.setGrid(component);
super.extend(component);
}
/**
+ * Adds a {@link DataGenerator} for this {@code RpcDataProviderExtension}.
+ * DataGenerators are called when sending row data to client. If given
+ * DataGenerator is already added, this method does nothing.
+ *
+ * @since 7.6
+ * @param generator
+ * generator to add
+ */
+ public void addDataGenerator(DataGenerator generator) {
+ dataGenerators.add(generator);
+ }
+
+ /**
+ * Removes a {@link DataGenerator} from this
+ * {@code RpcDataProviderExtension}. If given DataGenerator is not added to
+ * this data provider, this method does nothing.
+ *
+ * @since 7.6
+ * @param generator
+ * generator to remove
+ */
+ public void removeDataGenerator(DataGenerator generator) {
+ dataGenerators.remove(generator);
+ }
+
+ /**
* Informs the client side that new rows have been inserted into the data
* source.
*
@@ -1205,8 +661,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
rpc.insertRowData(index, count);
}
});
-
- activeRowHandler.insertRows(index, count);
}
/**
@@ -1231,8 +685,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
rpc.removeRowData(index, count);
}
});
-
- activeRowHandler.removeRows(index, count);
}
/**
@@ -1252,18 +704,20 @@ public class RpcDataProviderExtension extends AbstractExtension {
updatedItemIds.add(itemId);
}
- private void internalUpdateRowData(Object itemId) {
- int index = container.indexOfId(itemId);
- if (index >= 0) {
- JsonValue row = getRowData(getGrid().getColumns(), itemId);
- JsonArray rowArray = Json.createArray();
- rowArray.set(0, row);
- rpc.setRowData(index, rowArray);
+ private void internalUpdateRows(Set<Object> itemIds) {
+ if (itemIds.isEmpty()) {
+ return;
+ }
- if (isDetailsVisible(itemId)) {
- detailComponentManager.createDetails(itemId, index);
+ JsonArray rowData = Json.createArray();
+ int i = 0;
+ for (Object itemId : itemIds) {
+ if (activeItemHandler.getActiveItemIds().contains(itemId)) {
+ JsonObject row = getRowData(getGrid().getColumns(), itemId);
+ rowData.set(i++, row);
}
}
+ rpc.updateRowData(rowData);
}
/**
@@ -1280,20 +734,15 @@ public class RpcDataProviderExtension extends AbstractExtension {
public void setParent(ClientConnector parent) {
if (parent == null) {
// We're being detached, release various listeners
-
- activeRowHandler
- .removeValueChangeListeners(activeRowHandler.activeRange);
+ activeItemHandler.internalDropActiveItems(activeItemHandler
+ .getActiveItemIds());
if (container instanceof ItemSetChangeNotifier) {
((ItemSetChangeNotifier) container)
.removeItemSetChangeListener(itemListener);
}
- } else if (parent instanceof Grid) {
- Grid grid = (Grid) parent;
- rowReference = new RowReference(grid);
- cellReference = new CellReference(rowReference);
- } else {
+ } else if (!(parent instanceof Grid)) {
throw new IllegalStateException(
"Grid is the only accepted parent type");
}
@@ -1308,7 +757,13 @@ public class RpcDataProviderExtension extends AbstractExtension {
* a list of removed columns
*/
public void columnsRemoved(List<Column> removedColumns) {
- activeRowHandler.columnsRemoved(removedColumns);
+ for (GridValueChangeListener l : activeItemHandler
+ .getValueChangeListeners()) {
+ l.removeColumns(removedColumns);
+ }
+
+ // No need to resend unchanged data. Client will remember the old
+ // columns until next set of rows is sent.
}
/**
@@ -1318,11 +773,17 @@ public class RpcDataProviderExtension extends AbstractExtension {
* a list of added columns
*/
public void columnsAdded(List<Column> addedColumns) {
- activeRowHandler.columnsAdded(addedColumns);
+ for (GridValueChangeListener l : activeItemHandler
+ .getValueChangeListeners()) {
+ l.addColumns(addedColumns);
+ }
+
+ // Resend all rows to contain new data.
+ refreshCache();
}
- public DataProviderKeyMapper getKeyMapper() {
- return keyMapper;
+ public KeyMapper<Object> getKeyMapper() {
+ return activeItemHandler.keyMapper;
}
protected Grid getGrid() {
@@ -1330,62 +791,6 @@ public class RpcDataProviderExtension extends AbstractExtension {
}
/**
- * Converts and encodes the given data model property value using the given
- * converter and renderer. This method is public only for testing purposes.
- *
- * @param renderer
- * the renderer to use
- * @param converter
- * the converter to use
- * @param modelValue
- * the value to convert and encode
- * @param locale
- * the locale to use in conversion
- * @return an encoded value ready to be sent to the client
- */
- public static <T> JsonValue encodeValue(Object modelValue,
- Renderer<T> renderer, Converter<?, ?> converter, Locale locale) {
- Class<T> presentationType = renderer.getPresentationType();
- T presentationValue;
-
- if (converter == null) {
- try {
- presentationValue = presentationType.cast(modelValue);
- } catch (ClassCastException e) {
- if (presentationType == String.class) {
- // If there is no converter, just fallback to using
- // toString().
- // modelValue can't be null as Class.cast(null) will always
- // succeed
- presentationValue = (T) modelValue.toString();
- } else {
- throw new Converter.ConversionException(
- "Unable to convert value of type "
- + modelValue.getClass().getName()
- + " to presentation type "
- + presentationType.getName()
- + ". No converter is set and the types are not compatible.");
- }
- }
- } else {
- assert presentationType.isAssignableFrom(converter
- .getPresentationType());
- @SuppressWarnings("unchecked")
- Converter<T, Object> safeConverter = (Converter<T, Object>) converter;
- presentationValue = safeConverter.convertToPresentation(modelValue,
- safeConverter.getPresentationType(), locale);
- }
-
- JsonValue encodedValue = renderer.encode(presentationValue);
-
- return encodedValue;
- }
-
- private static Logger getLogger() {
- return Logger.getLogger(RpcDataProviderExtension.class.getName());
- }
-
- /**
* Marks a row's details to be visible or hidden.
* <p>
* If that row is currently in the client side's cache, this information
@@ -1399,37 +804,21 @@ public class RpcDataProviderExtension extends AbstractExtension {
* hide
*/
public void setDetailsVisible(Object itemId, boolean visible) {
- final boolean modified;
-
if (visible) {
- modified = visibleDetails.add(itemId);
+ visibleDetails.add(itemId);
/*
- * We don't want to create the component here, since the component
- * might be out of view, and thus we don't know where the details
- * should end up on the client side. This is also a great thing to
- * optimize away, so that in case a lot of things would be opened at
- * once, a huge chunk of data doesn't get sent over immediately.
+ * This might be an issue with a huge number of open rows, but as of
+ * now this works in most of the cases.
*/
-
+ detailComponentManager.createDetails(itemId);
} else {
- modified = visibleDetails.remove(itemId);
+ visibleDetails.remove(itemId);
- /*
- * Here we can try to destroy the component no matter what. The
- * component has been removed and should be detached from the
- * component hierarchy. The details row will be closed on the client
- * side automatically.
- */
detailComponentManager.destroyDetails(itemId);
}
- int rowIndex = indexOf(itemId);
- boolean modifiedRowIsActive = activeRowHandler.activeRange
- .contains(rowIndex);
- if (modified && modifiedRowIsActive) {
- updateRowData(itemId);
- }
+ updateRowData(itemId);
}
/**
@@ -1454,18 +843,10 @@ public class RpcDataProviderExtension extends AbstractExtension {
public void refreshDetails() {
for (Object itemId : ImmutableSet.copyOf(visibleDetails)) {
detailComponentManager.refresh(itemId);
+ updateRowData(itemId);
}
}
- private int indexOf(Object itemId) {
- /*
- * It would be great if we could optimize this method away, since the
- * normal usage of Grid doesn't need any indices to be known. It was
- * already optimized away once, maybe we can do away with these as well.
- */
- return container.indexOfId(itemId);
- }
-
/**
* Gets the detail component manager for this data provider
*
@@ -1475,13 +856,4 @@ public class RpcDataProviderExtension extends AbstractExtension {
public DetailComponentManager getDetailComponentManager() {
return detailComponentManager;
}
-
- @Override
- public void detach() {
- for (Object itemId : ImmutableSet.copyOf(visibleDetails)) {
- detailComponentManager.destroyDetails(itemId);
- }
-
- super.detach();
- }
}
diff --git a/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java b/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java
index 4bb4e4c1b2..4329219e96 100644
--- a/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java
+++ b/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java
@@ -51,12 +51,14 @@ public class ContainerOrderedWrapper implements Container.Ordered,
private final Container container;
/**
- * Ordering information, ie. the mapping from Item ID to the next item ID
+ * Ordering information, ie. the mapping from Item ID to the next item ID.
+ * The last item id should not be present
*/
private Hashtable<Object, Object> next;
/**
- * Reverse ordering information for convenience and performance reasons.
+ * Reverse ordering information for convenience and performance reasons. The
+ * first item id should not be present
*/
private Hashtable<Object, Object> prev;
@@ -124,13 +126,21 @@ public class ContainerOrderedWrapper implements Container.Ordered,
first = nid;
}
if (last.equals(id)) {
- first = pid;
+ last = pid;
}
if (nid != null) {
- prev.put(nid, pid);
+ if (pid == null) {
+ prev.remove(nid);
+ } else {
+ prev.put(nid, pid);
+ }
}
if (pid != null) {
- next.put(pid, nid);
+ if (nid == null) {
+ next.remove(pid);
+ } else {
+ next.put(pid, nid);
+ }
}
next.remove(id);
prev.remove(id);
@@ -200,7 +210,7 @@ public class ContainerOrderedWrapper implements Container.Ordered,
final Collection<?> ids = container.getItemIds();
// Recreates ordering if some parts of it are missing
- if (next == null || first == null || last == null || prev != null) {
+ if (next == null || first == null || last == null || prev == null) {
first = null;
last = null;
next = new Hashtable<Object, Object>();
@@ -219,7 +229,7 @@ public class ContainerOrderedWrapper implements Container.Ordered,
// Adds missing items
for (final Iterator<?> i = ids.iterator(); i.hasNext();) {
final Object id = i.next();
- if (!next.containsKey(id)) {
+ if (!next.containsKey(id) && last != id) {
addToOrderWrapper(id);
}
}
diff --git a/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java b/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java
index 0e802da879..f965cfcc6a 100644
--- a/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java
+++ b/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java
@@ -19,20 +19,43 @@ package com.vaadin.data.util.converter;
import java.util.Locale;
/**
- * A converter that converts from {@link String} to {@link Boolean} and back.
- * The String representation is given by Boolean.toString().
- * <p>
- * Leading and trailing white spaces are ignored when converting from a String.
- * </p>
- *
+ * A converter that converts from {@link String} to {@link Boolean} and back. The String representation is given by
+ * {@link Boolean#toString()} or provided in constructor {@link #StringToBooleanConverter(String, String)}.
+ * <p> Leading and trailing white spaces are ignored when converting from a String. </p>
+ * <p> For language-dependent representation, subclasses should overwrite {@link #getFalseString(Locale)} and {@link #getTrueString(Locale)}</p>
+ *
* @author Vaadin Ltd
* @since 7.0
*/
public class StringToBooleanConverter implements Converter<String, Boolean> {
+ private final String trueString;
+
+ private final String falseString;
+
+ /**
+ * Creates converter with default string representations - "true" and "false"
+ *
+ */
+ public StringToBooleanConverter() {
+ this(Boolean.TRUE.toString(), Boolean.FALSE.toString());
+ }
+
+ /**
+ * Creates converter with custom string representation.
+ *
+ * @since 7.5.4
+ * @param falseString string representation for <code>false</code>
+ * @param trueString string representation for <code>true</code>
+ */
+ public StringToBooleanConverter(String trueString, String falseString) {
+ this.trueString = trueString;
+ this.falseString = falseString;
+ }
+
/*
* (non-Javadoc)
- *
+ *
* @see
* com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object,
* java.lang.Class, java.util.Locale)
@@ -59,26 +82,26 @@ public class StringToBooleanConverter implements Converter<String, Boolean> {
}
/**
- * Gets the string representation for true. Default is "true".
- *
+ * Gets the string representation for true. Default is "true", if not set in constructor.
+ *
* @return the string representation for true
*/
protected String getTrueString() {
- return Boolean.TRUE.toString();
+ return trueString;
}
/**
- * Gets the string representation for false. Default is "false".
- *
+ * Gets the string representation for false. Default is "false", if not set in constructor.
+ *
* @return the string representation for false
*/
protected String getFalseString() {
- return Boolean.FALSE.toString();
+ return falseString;
}
/*
* (non-Javadoc)
- *
+ *
* @see
* com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang
* .Object, java.lang.Class, java.util.Locale)
@@ -91,15 +114,39 @@ public class StringToBooleanConverter implements Converter<String, Boolean> {
return null;
}
if (value) {
- return getTrueString();
+ return getTrueString(locale);
} else {
- return getFalseString();
+ return getFalseString(locale);
}
}
+ /**
+ * Gets the locale-depended string representation for false.
+ * Default is locale-independent value provided by {@link #getFalseString()}
+ *
+ * @since 7.5.4
+ * @param locale to be used
+ * @return the string representation for false
+ */
+ protected String getFalseString(Locale locale) {
+ return getFalseString();
+ }
+
+ /**
+ * Gets the locale-depended string representation for true.
+ * Default is locale-independent value provided by {@link #getTrueString()}
+ *
+ * @since 7.5.4
+ * @param locale to be used
+ * @return the string representation for true
+ */
+ protected String getTrueString(Locale locale) {
+ return getTrueString();
+ }
+
/*
* (non-Javadoc)
- *
+ *
* @see com.vaadin.data.util.converter.Converter#getModelType()
*/
@Override
@@ -109,7 +156,7 @@ public class StringToBooleanConverter implements Converter<String, Boolean> {
/*
* (non-Javadoc)
- *
+ *
* @see com.vaadin.data.util.converter.Converter#getPresentationType()
*/
@Override
diff --git a/server/src/com/vaadin/event/ShortcutAction.java b/server/src/com/vaadin/event/ShortcutAction.java
index 09accae1c7..dd511c23c0 100644
--- a/server/src/com/vaadin/event/ShortcutAction.java
+++ b/server/src/com/vaadin/event/ShortcutAction.java
@@ -17,6 +17,7 @@
package com.vaadin.event;
import java.io.Serializable;
+import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -55,7 +56,7 @@ public class ShortcutAction extends Action {
private final int keyCode;
- private final int[] modifiers;
+ private int[] modifiers;
/**
* Creates a shortcut that reacts to the given {@link KeyCode} and
@@ -73,7 +74,7 @@ public class ShortcutAction extends Action {
public ShortcutAction(String caption, int kc, int... m) {
super(caption);
keyCode = kc;
- modifiers = m;
+ setModifiers(m);
}
/**
@@ -94,7 +95,7 @@ public class ShortcutAction extends Action {
public ShortcutAction(String caption, Resource icon, int kc, int... m) {
super(caption, icon);
keyCode = kc;
- modifiers = m;
+ setModifiers(m);
}
/**
@@ -190,7 +191,7 @@ public class ShortcutAction extends Action {
// Given modifiers override this indicated in the caption
if (modifierKeys != null) {
- modifiers = modifierKeys;
+ setModifiers(modifierKeys);
} else {
// Read modifiers from caption
int[] mod = new int[match.length() - 1];
@@ -208,13 +209,30 @@ public class ShortcutAction extends Action {
break;
}
}
- modifiers = mod;
+ setModifiers(mod);
}
} else {
keyCode = -1;
- modifiers = modifierKeys;
+ setModifiers(modifierKeys);
}
+
+ }
+
+ /**
+ * When setting modifiers, make sure that modifiers is a valid array AND
+ * that it's sorted.
+ *
+ * @param modifiers
+ * the modifier keys for this shortcut
+ */
+ private void setModifiers(int... modifiers) {
+ if (modifiers == null) {
+ this.modifiers = new int[0];
+ } else {
+ this.modifiers = modifiers;
+ }
+ Arrays.sort(this.modifiers);
}
/**
diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java
index 5a0d852299..77a1a3134e 100644
--- a/server/src/com/vaadin/server/Constants.java
+++ b/server/src/com/vaadin/server/Constants.java
@@ -137,6 +137,7 @@ public interface Constants {
static final String SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING = "legacyPropertyToString";
static final String SERVLET_PARAMETER_SYNC_ID_CHECK = "syncIdCheck";
static final String SERVLET_PARAMETER_SENDURLSASPARAMETERS = "sendUrlsAsParameters";
+ static final String SERVLET_PARAMETER_PUSH_SUSPEND_TIMEOUT_LONGPOLLING = "pushLongPollingSuspendTimeout";
// Configurable parameter names
static final String PARAMETER_VAADIN_RESOURCES = "Resources";
diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java
index 7aada2402d..61df02feaa 100644
--- a/server/src/com/vaadin/server/VaadinServlet.java
+++ b/server/src/com/vaadin/server/VaadinServlet.java
@@ -28,6 +28,7 @@ import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -694,17 +695,20 @@ public class VaadinServlet extends HttpServlet implements Constants {
return false;
}
+ String decodedRequestURI = URLDecoder.decode(request.getRequestURI(),
+ "UTF-8");
if ((request.getContextPath() != null)
- && (request.getRequestURI().startsWith("/VAADIN/"))) {
- serveStaticResourcesInVAADIN(request.getRequestURI(), request,
- response);
+ && (decodedRequestURI.startsWith("/VAADIN/"))) {
+ serveStaticResourcesInVAADIN(decodedRequestURI, request, response);
return true;
- } else if (request.getRequestURI().startsWith(
- request.getContextPath() + "/VAADIN/")) {
+ }
+
+ String decodedContextPath = URLDecoder.decode(request.getContextPath(),
+ "UTF-8");
+ if (decodedRequestURI.startsWith(decodedContextPath + "/VAADIN/")) {
serveStaticResourcesInVAADIN(
- request.getRequestURI().substring(
- request.getContextPath().length()), request,
- response);
+ decodedRequestURI.substring(decodedContextPath.length()),
+ request, response);
return true;
}
diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java
index 66018b02f2..9bf30cb3db 100644
--- a/server/src/com/vaadin/server/WebBrowser.java
+++ b/server/src/com/vaadin/server/WebBrowser.java
@@ -126,6 +126,20 @@ public class WebBrowser implements Serializable {
}
/**
+ * Tests whether the user is using Edge.
+ *
+ * @return true if the user is using Edge, false if the user is not using
+ * Edge or if no information on the browser is present
+ */
+ public boolean isEdge() {
+ if (browserDetails == null) {
+ return false;
+ }
+
+ return browserDetails.isEdge();
+ }
+
+ /**
* Tests whether the user is using Safari.
*
* @return true if the user is using Safari, false if the user is not using
diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
index 87ce9ba81a..5c0d2e14d4 100644
--- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
+++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
@@ -26,7 +26,9 @@ import java.io.Writer;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
+import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.atmosphere.cpr.AtmosphereResource;
@@ -274,6 +276,13 @@ public class AtmospherePushConnection implements PushConnection {
public void disconnect() {
assert isConnected();
+ if (resource == null) {
+ // Already disconnected. Should not happen but if it does, we don't
+ // want to cause NPEs
+ getLogger()
+ .fine("AtmospherePushConnection.disconnect() called twice, this should not happen");
+ return;
+ }
if (resource.isResumed()) {
// This can happen for long polling because of
// http://dev.vaadin.com/ticket/16919
@@ -345,4 +354,32 @@ public class AtmospherePushConnection implements PushConnection {
private static Logger getLogger() {
return Logger.getLogger(AtmospherePushConnection.class.getName());
}
+
+ /**
+ * Internal method used for reconfiguring loggers to show all Atmosphere log
+ * messages in the console.
+ *
+ * @since 7.6
+ */
+ public static void enableAtmosphereDebugLogging() {
+ Level level = Level.FINEST;
+
+ Logger atmosphereLogger = Logger.getLogger("org.atmosphere");
+ if (atmosphereLogger.getLevel() == level) {
+ // Already enabled
+ return;
+ }
+
+ atmosphereLogger.setLevel(level);
+
+ // Without this logging, we will have a ClassCircularityError
+ LogRecord record = new LogRecord(Level.INFO,
+ "Enabling Atmosphere debug logging");
+ atmosphereLogger.log(record);
+
+ ConsoleHandler ch = new ConsoleHandler();
+ ch.setLevel(Level.ALL);
+ atmosphereLogger.addHandler(ch);
+ }
+
}
diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java
index 576cbd8411..532c7fe95b 100644
--- a/server/src/com/vaadin/server/communication/FileUploadHandler.java
+++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java
@@ -269,7 +269,7 @@ public class FileUploadHandler implements RequestHandler {
streamVariable = uI.getConnectorTracker().getStreamVariable(
connectorId, variableName);
String secKey = uI.getConnectorTracker().getSeckey(streamVariable);
- if (!secKey.equals(parts[3])) {
+ if (secKey == null || !secKey.equals(parts[3])) {
// TODO Should rethink error handling
return true;
}
diff --git a/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java b/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java
index f36d403dd5..6d2843a4fc 100644
--- a/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java
+++ b/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java
@@ -181,8 +181,13 @@ public class JSR356WebsocketInitializer implements ServletContextListener {
*/
protected boolean isVaadinServlet(ServletRegistration servletRegistration) {
try {
- Class<?> servletClass = Class.forName(servletRegistration
- .getClassName());
+ String servletClassName = servletRegistration.getClassName();
+ if (servletClassName.equals("com.ibm.ws.wsoc.WsocServlet")) {
+ // Websphere servlet which implements websocket endpoints,
+ // dynamically added
+ return false;
+ }
+ Class<?> servletClass = Class.forName(servletClassName);
return VaadinServlet.class.isAssignableFrom(servletClass);
} catch (Exception e) {
// This will fail in OSGi environments, assume everything is a
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java
index 01077c3f86..994415a0b4 100644
--- a/server/src/com/vaadin/server/communication/PushHandler.java
+++ b/server/src/com/vaadin/server/communication/PushHandler.java
@@ -55,6 +55,8 @@ import elemental.json.JsonException;
*/
public class PushHandler {
+ private int longPollingSuspendTimeout = -1;
+
/**
* Callback interface used internally to process an event with the
* corresponding UI properly locked.
@@ -107,7 +109,7 @@ public class PushHandler {
return;
}
- resource.suspend();
+ suspend(resource);
AtmospherePushConnection connection = getConnectionForUI(ui);
assert (connection != null);
@@ -174,6 +176,21 @@ public class PushHandler {
}
/**
+ * Suspends the given resource
+ *
+ * @since
+ * @param resource
+ * the resource to suspend
+ */
+ protected void suspend(AtmosphereResource resource) {
+ if (resource.transport() == TRANSPORT.LONG_POLLING) {
+ resource.suspend(getLongPollingSuspendTimeout());
+ } else {
+ resource.suspend(-1);
+ }
+ }
+
+ /**
* Find the UI for the atmosphere resource, lock it and invoke the callback.
*
* @param resource
@@ -493,4 +510,26 @@ public class PushHandler {
resource.transport() == TRANSPORT.WEBSOCKET);
}
+ /**
+ * Sets the timeout used for suspend calls when using long polling.
+ *
+ * If you are using a proxy with a defined idle timeout, set the suspend
+ * timeout to a value smaller than the proxy timeout so that the server is
+ * aware of a reconnect taking place.
+ *
+ * @param suspendTimeout
+ * the timeout to use for suspended AtmosphereResources
+ */
+ public void setLongPollingSuspendTimeout(int longPollingSuspendTimeout) {
+ this.longPollingSuspendTimeout = longPollingSuspendTimeout;
+ }
+
+ /**
+ * Gets the timeout used for suspend calls when using long polling.
+ *
+ * @return the timeout to use for suspended AtmosphereResources
+ */
+ public int getLongPollingSuspendTimeout() {
+ return longPollingSuspendTimeout;
+ }
}
diff --git a/server/src/com/vaadin/server/communication/PushRequestHandler.java b/server/src/com/vaadin/server/communication/PushRequestHandler.java
index c01c74e5cd..c44fcd9ef3 100644
--- a/server/src/com/vaadin/server/communication/PushRequestHandler.java
+++ b/server/src/com/vaadin/server/communication/PushRequestHandler.java
@@ -77,7 +77,7 @@ public class PushRequestHandler implements RequestHandler,
final ServletConfig vaadinServletConfig = service.getServlet()
.getServletConfig();
- pushHandler = new PushHandler(service);
+ pushHandler = createPushHandler(service);
atmosphere = getPreInitializedAtmosphere(vaadinServletConfig);
if (atmosphere == null) {
@@ -100,7 +100,12 @@ public class PushRequestHandler implements RequestHandler,
"Using pre-initialized Atmosphere for servlet "
+ vaadinServletConfig.getServletName());
}
-
+ pushHandler
+ .setLongPollingSuspendTimeout(atmosphere
+ .getAtmosphereConfig()
+ .getInitParameter(
+ com.vaadin.server.Constants.SERVLET_PARAMETER_PUSH_SUSPEND_TIMEOUT_LONGPOLLING,
+ -1));
for (AtmosphereHandlerWrapper handlerWrapper : atmosphere
.getAtmosphereHandlers().values()) {
AtmosphereHandler handler = handlerWrapper.atmosphereHandler;
@@ -113,6 +118,22 @@ public class PushRequestHandler implements RequestHandler,
}
}
+ /**
+ * Creates a push handler for this request handler.
+ * <p>
+ * Create your own request handler and override this method if you want to
+ * customize the {@link PushHandler}, e.g. to dynamically decide the suspend
+ * timeout.
+ *
+ * @since
+ * @param service
+ * the vaadin service
+ * @return the push handler to use for this service
+ */
+ protected PushHandler createPushHandler(VaadinServletService service) {
+ return new PushHandler(service);
+ }
+
private static final Logger getLogger() {
return Logger.getLogger(PushRequestHandler.class.getName());
}
diff --git a/server/src/com/vaadin/ui/AbstractFocusable.java b/server/src/com/vaadin/ui/AbstractFocusable.java
new file mode 100644
index 0000000000..ad3b96f29b
--- /dev/null
+++ b/server/src/com/vaadin/ui/AbstractFocusable.java
@@ -0,0 +1,134 @@
+/*
+ * 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.ui;
+
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.BlurNotifier;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.event.FieldEvents.FocusNotifier;
+import com.vaadin.shared.ui.TabIndexState;
+import com.vaadin.ui.Component.Focusable;
+
+/**
+ * An abstract base class for focusable components. Includes API for setting the
+ * tab index, programmatic focusing, and adding focus and blur listeners.
+ *
+ * @since 7.6
+ * @author Vaadin Ltd
+ */
+public abstract class AbstractFocusable extends AbstractComponent implements
+ Focusable, FocusNotifier, BlurNotifier {
+
+ protected AbstractFocusable() {
+ registerRpc(new FocusAndBlurServerRpcImpl(this) {
+ @Override
+ protected void fireEvent(Event event) {
+ AbstractFocusable.this.fireEvent(event);
+ }
+ });
+ }
+
+ @Override
+ public void addBlurListener(BlurListener listener) {
+ addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)}
+ */
+ @Override
+ @Deprecated
+ public void addListener(BlurListener listener) {
+ addBlurListener(listener);
+ }
+
+ @Override
+ public void removeBlurListener(BlurListener listener) {
+ removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #removeBlurListener(BlurListener)}
+ */
+ @Override
+ @Deprecated
+ public void removeListener(BlurListener listener) {
+ removeBlurListener(listener);
+
+ }
+
+ @Override
+ public void addFocusListener(FocusListener listener) {
+ addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+ FocusListener.focusMethod);
+
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #addFocusListener(FocusListener)}
+ */
+ @Override
+ @Deprecated
+ public void addListener(FocusListener listener) {
+ addFocusListener(listener);
+ }
+
+ @Override
+ public void removeFocusListener(FocusListener listener) {
+ removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+ }
+
+ /**
+ * @deprecated As of 7.0, replaced by
+ * {@link #removeFocusListener(FocusListener)}
+ */
+ @Override
+ @Deprecated
+ public void removeListener(FocusListener listener) {
+ removeFocusListener(listener);
+ }
+
+ @Override
+ public void focus() {
+ super.focus();
+ }
+
+ @Override
+ public int getTabIndex() {
+ return getState(false).tabIndex;
+ }
+
+ @Override
+ public void setTabIndex(int tabIndex) {
+ getState().tabIndex = tabIndex;
+ }
+
+ @Override
+ protected TabIndexState getState() {
+ return (TabIndexState) super.getState();
+ }
+
+ @Override
+ protected TabIndexState getState(boolean markAsDirty) {
+ return (TabIndexState) super.getState(markAsDirty);
+ }
+}
diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java
index 6beb6ed686..a918780a60 100644
--- a/server/src/com/vaadin/ui/Button.java
+++ b/server/src/com/vaadin/ui/Button.java
@@ -24,12 +24,7 @@ import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import com.vaadin.event.Action;
-import com.vaadin.event.FieldEvents;
-import com.vaadin.event.FieldEvents.BlurEvent;
-import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
-import com.vaadin.event.FieldEvents.FocusEvent;
-import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.ShortcutAction;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
@@ -38,7 +33,6 @@ import com.vaadin.server.Resource;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.ButtonState;
-import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.util.ReflectTools;
@@ -50,8 +44,7 @@ import com.vaadin.util.ReflectTools;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class Button extends AbstractComponent implements
- FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Focusable,
+public class Button extends AbstractFocusable implements
Action.ShortcutNotifier {
private ButtonServerRpc rpc = new ButtonServerRpc() {
@@ -72,20 +65,11 @@ public class Button extends AbstractComponent implements
}
};
- FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) {
-
- @Override
- protected void fireEvent(Event event) {
- Button.this.fireEvent(event);
- }
- };
-
/**
* Creates a new push button.
*/
public Button() {
registerRpc(rpc);
- registerRpc(focusBlurRpc);
}
/**
@@ -393,67 +377,6 @@ public class Button extends AbstractComponent implements
fireEvent(new Button.ClickEvent(this, details));
}
- @Override
- public void addBlurListener(BlurListener listener) {
- addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
- BlurListener.blurMethod);
- }
-
- /**
- * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)}
- **/
- @Override
- @Deprecated
- public void addListener(BlurListener listener) {
- addBlurListener(listener);
- }
-
- @Override
- public void removeBlurListener(BlurListener listener) {
- removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeBlurListener(BlurListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(BlurListener listener) {
- removeBlurListener(listener);
- }
-
- @Override
- public void addFocusListener(FocusListener listener) {
- addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
- FocusListener.focusMethod);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addFocusListener(FocusListener)}
- **/
- @Override
- @Deprecated
- public void addListener(FocusListener listener) {
- addFocusListener(listener);
- }
-
- @Override
- public void removeFocusListener(FocusListener listener) {
- removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeFocusListener(FocusListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(FocusListener listener) {
- removeFocusListener(listener);
- }
-
/*
* Actions
*/
@@ -575,32 +498,6 @@ public class Button extends AbstractComponent implements
getState().disableOnClick = disableOnClick;
}
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#getTabIndex()
- */
- @Override
- public int getTabIndex() {
- return getState(false).tabIndex;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
- */
- @Override
- public void setTabIndex(int tabIndex) {
- getState().tabIndex = tabIndex;
- }
-
- @Override
- public void focus() {
- // Overridden only to make public
- super.focus();
- }
-
@Override
protected ButtonState getState() {
return (ButtonState) super.getState();
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index e9469c5bca..215df3a6a3 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -31,6 +31,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -45,14 +46,17 @@ import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.google.gwt.thirdparty.guava.common.collect.Sets.SetView;
import com.vaadin.data.Container;
import com.vaadin.data.Container.Indexed;
+import com.vaadin.data.Container.ItemSetChangeEvent;
+import com.vaadin.data.Container.ItemSetChangeListener;
+import com.vaadin.data.Container.ItemSetChangeNotifier;
import com.vaadin.data.Container.PropertySetChangeEvent;
import com.vaadin.data.Container.PropertySetChangeListener;
import com.vaadin.data.Container.PropertySetChangeNotifier;
import com.vaadin.data.Container.Sortable;
+import com.vaadin.data.DataGenerator;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.RpcDataProviderExtension;
-import com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper;
import com.vaadin.data.RpcDataProviderExtension.DetailComponentManager;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.fieldgroup.DefaultFieldGroupFieldFactory;
@@ -77,6 +81,7 @@ import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.EncodeResult;
import com.vaadin.server.ErrorMessage;
+import com.vaadin.server.Extension;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.KeyMapper;
import com.vaadin.server.VaadinSession;
@@ -89,13 +94,16 @@ import com.vaadin.shared.ui.grid.GridColumnState;
import com.vaadin.shared.ui.grid.GridConstants;
import com.vaadin.shared.ui.grid.GridServerRpc;
import com.vaadin.shared.ui.grid.GridState;
-import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode;
import com.vaadin.shared.ui.grid.GridStaticCellType;
import com.vaadin.shared.ui.grid.GridStaticSectionState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState;
import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState;
import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.shared.ui.grid.ScrollDestination;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelState;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
@@ -106,7 +114,6 @@ import com.vaadin.ui.renderers.TextRenderer;
import com.vaadin.util.ReflectTools;
import elemental.json.Json;
-import elemental.json.JsonArray;
import elemental.json.JsonObject;
import elemental.json.JsonValue;
@@ -172,7 +179,7 @@ import elemental.json.JsonValue;
* @since 7.4
* @author Vaadin Ltd
*/
-public class Grid extends AbstractComponent implements SelectionNotifier,
+public class Grid extends AbstractFocusable implements SelectionNotifier,
SortNotifier, SelectiveRenderer, ItemClickNotifier {
/**
@@ -511,6 +518,100 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
+ * Interface for an editor event listener
+ */
+ public interface EditorListener extends Serializable {
+
+ public static final Method EDITOR_OPEN_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorOpened",
+ EditorOpenEvent.class);
+ public static final Method EDITOR_MOVE_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorMoved",
+ EditorMoveEvent.class);
+ public static final Method EDITOR_CLOSE_METHOD = ReflectTools
+ .findMethod(EditorListener.class, "editorClosed",
+ EditorCloseEvent.class);
+
+ /**
+ * Called when an editor is opened
+ *
+ * @param e
+ * an editor open event object
+ */
+ public void editorOpened(EditorOpenEvent e);
+
+ /**
+ * Called when an editor is reopened without closing it first
+ *
+ * @param e
+ * an editor move event object
+ */
+ public void editorMoved(EditorMoveEvent e);
+
+ /**
+ * Called when an editor is closed
+ *
+ * @param e
+ * an editor close event object
+ */
+ public void editorClosed(EditorCloseEvent e);
+
+ }
+
+ /**
+ * Base class for editor related events
+ */
+ public static abstract class EditorEvent extends Component.Event {
+
+ private Object itemID;
+
+ protected EditorEvent(Grid source, Object itemID) {
+ super(source);
+ this.itemID = itemID;
+ }
+
+ /**
+ * Get the item (row) for which this editor was opened
+ */
+ public Object getItem() {
+ return itemID;
+ }
+
+ }
+
+ /**
+ * This event gets fired when an editor is opened
+ */
+ public static class EditorOpenEvent extends EditorEvent {
+
+ public EditorOpenEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
+ * This event gets fired when an editor is opened while another row is being
+ * edited (i.e. editor focus moves elsewhere)
+ */
+ public static class EditorMoveEvent extends EditorEvent {
+
+ public EditorMoveEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
+ * This event gets fired when an editor is dismissed or closed by other
+ * means.
+ */
+ public static class EditorCloseEvent extends EditorEvent {
+
+ public EditorCloseEvent(Grid source, Object itemID) {
+ super(source, itemID);
+ }
+ }
+
+ /**
* Default error handler for the editor
*
*/
@@ -611,8 +712,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
/**
* The server-side interface that controls Grid's selection state.
+ * SelectionModel should extend {@link AbstractGridExtension}.
*/
- public interface SelectionModel extends Serializable {
+ public interface SelectionModel extends Serializable, Extension {
/**
* Checks whether an item is selected or not.
*
@@ -631,6 +733,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
/**
* Injects the current {@link Grid} instance into the SelectionModel.
+ * This method should usually call the extend method of
+ * {@link AbstractExtension}.
* <p>
* <em>Note:</em> This method should not be called manually.
*
@@ -872,10 +976,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* A base class for SelectionModels that contains some of the logic that is
* reusable.
*/
- public static abstract class AbstractSelectionModel implements
- SelectionModel {
+ public static abstract class AbstractSelectionModel extends
+ AbstractGridExtension implements SelectionModel, DataGenerator {
protected final LinkedHashSet<Object> selection = new LinkedHashSet<Object>();
- protected Grid grid = null;
@Override
public boolean isSelected(final Object itemId) {
@@ -889,7 +992,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public void setGrid(final Grid grid) {
- this.grid = grid;
+ if (grid != null) {
+ extend(grid);
+ }
}
/**
@@ -903,7 +1008,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
protected void checkItemIdExists(Object itemId)
throws IllegalArgumentException {
- if (!grid.getContainerDataSource().containsId(itemId)) {
+ if (!getParentGrid().getContainerDataSource().containsId(itemId)) {
throw new IllegalArgumentException("Given item id (" + itemId
+ ") does not exist in the container");
}
@@ -945,7 +1050,19 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
protected void fireSelectionEvent(
final Collection<Object> oldSelection,
final Collection<Object> newSelection) {
- grid.fireSelectionEvent(oldSelection, newSelection);
+ getParentGrid().fireSelectionEvent(oldSelection, newSelection);
+ }
+
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ if (isSelected(itemId)) {
+ rowData.put(GridState.JSONKEY_SELECTED, true);
+ }
+ }
+
+ @Override
+ protected Object getItemId(String rowKey) {
+ return rowKey != null ? super.getItemId(rowKey) : null;
}
}
@@ -954,8 +1071,25 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
public static class SingleSelectionModel extends AbstractSelectionModel
implements SelectionModel.Single {
+
+ @Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+ registerRpc(new SingleSelectionModelServerRpc() {
+
+ @Override
+ public void select(String rowKey) {
+ SingleSelectionModel.this.select(getItemId(rowKey), false);
+ }
+ });
+ }
+
@Override
public boolean select(final Object itemId) {
+ return select(itemId, true);
+ }
+
+ protected boolean select(final Object itemId, boolean refresh) {
if (itemId == null) {
return deselect(getSelectedRow());
}
@@ -967,7 +1101,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
if (modified) {
final Collection<Object> deselected;
if (selectedRow != null) {
- deselectInternal(selectedRow, false);
+ deselectInternal(selectedRow, false, true);
deselected = Collections.singleton(selectedRow);
} else {
deselected = Collections.emptySet();
@@ -976,19 +1110,28 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
fireSelectionEvent(deselected, selection);
}
+ if (refresh) {
+ refreshRow(itemId);
+ }
+
return modified;
}
private boolean deselect(final Object itemId) {
- return deselectInternal(itemId, true);
+ return deselectInternal(itemId, true, true);
}
private boolean deselectInternal(final Object itemId,
- boolean fireEventIfNeeded) {
+ boolean fireEventIfNeeded, boolean refresh) {
final boolean modified = selection.remove(itemId);
- if (fireEventIfNeeded && modified) {
- fireSelectionEvent(Collections.singleton(itemId),
- Collections.emptySet());
+ if (modified) {
+ if (refresh) {
+ refreshRow(itemId);
+ }
+ if (fireEventIfNeeded) {
+ fireSelectionEvent(Collections.singleton(itemId),
+ Collections.emptySet());
+ }
}
return modified;
}
@@ -1014,23 +1157,25 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public void setDeselectAllowed(boolean deselectAllowed) {
- grid.getState().singleSelectDeselectAllowed = deselectAllowed;
+ getState().deselectAllowed = deselectAllowed;
}
@Override
public boolean isDeselectAllowed() {
- return grid.getState(false).singleSelectDeselectAllowed;
+ return getState().deselectAllowed;
+ }
+
+ @Override
+ protected SingleSelectionModelState getState() {
+ return (SingleSelectionModelState) super.getState();
}
}
/**
* A default implementation for a {@link SelectionModel.None}
*/
- public static class NoSelectionModel implements SelectionModel.None {
- @Override
- public void setGrid(final Grid grid) {
- // NOOP, not needed for anything
- }
+ public static class NoSelectionModel extends AbstractSelectionModel
+ implements SelectionModel.None {
@Override
public boolean isSelected(final Object itemId) {
@@ -1069,6 +1214,41 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
private int selectionLimit = DEFAULT_MAX_SELECTIONS;
@Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+ registerRpc(new MultiSelectionModelServerRpc() {
+
+ @Override
+ public void select(List<String> rowKeys) {
+ List<Object> items = new ArrayList<Object>();
+ for (String rowKey : rowKeys) {
+ items.add(getItemId(rowKey));
+ }
+ MultiSelectionModel.this.select(items, false);
+ }
+
+ @Override
+ public void deselect(List<String> rowKeys) {
+ List<Object> items = new ArrayList<Object>();
+ for (String rowKey : rowKeys) {
+ items.add(getItemId(rowKey));
+ }
+ MultiSelectionModel.this.deselect(items, false);
+ }
+
+ @Override
+ public void selectAll() {
+ MultiSelectionModel.this.selectAll(false);
+ }
+
+ @Override
+ public void deselectAll() {
+ MultiSelectionModel.this.deselectAll(false);
+ }
+ });
+ }
+
+ @Override
public boolean select(final Object... itemIds)
throws IllegalArgumentException {
if (itemIds != null) {
@@ -1089,6 +1269,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public boolean select(final Collection<?> itemIds)
throws IllegalArgumentException {
+ return select(itemIds, true);
+ }
+
+ protected boolean select(final Collection<?> itemIds, boolean refresh) {
if (itemIds == null) {
throw new IllegalArgumentException("itemIds may not be null");
}
@@ -1113,6 +1297,15 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
fireSelectionEvent(oldSelection, selection);
}
+
+ updateAllSelectedState();
+
+ if (refresh) {
+ for (Object itemId : itemIds) {
+ refreshRow(itemId);
+ }
+ }
+
return selectionWillChange;
}
@@ -1166,6 +1359,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public boolean deselect(final Collection<?> itemIds)
throws IllegalArgumentException {
+ return deselect(itemIds, true);
+ }
+
+ protected boolean deselect(final Collection<?> itemIds, boolean refresh) {
if (itemIds == null) {
throw new IllegalArgumentException("itemIds may not be null");
}
@@ -1178,15 +1375,28 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
selection.removeAll(itemIds);
fireSelectionEvent(oldSelection, selection);
}
+
+ updateAllSelectedState();
+
+ if (refresh) {
+ for (Object itemId : itemIds) {
+ refreshRow(itemId);
+ }
+ }
+
return hasCommonElements;
}
@Override
public boolean selectAll() {
+ return selectAll(true);
+ }
+
+ protected boolean selectAll(boolean refresh) {
// select will fire the event
- final Indexed container = grid.getContainerDataSource();
+ final Indexed container = getParentGrid().getContainerDataSource();
if (container != null) {
- return select(container.getItemIds());
+ return select(container.getItemIds(), refresh);
} else if (selection.isEmpty()) {
return false;
} else {
@@ -1195,14 +1405,18 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* but I guess the only theoretically correct course of
* action...
*/
- return deselectAll();
+ return deselectAll(false);
}
}
@Override
public boolean deselectAll() {
+ return deselectAll(true);
+ }
+
+ protected boolean deselectAll(boolean refresh) {
// deselect will fire the event
- return deselect(getSelectedRows());
+ return deselect(getSelectedRows(), refresh);
}
/**
@@ -1258,6 +1472,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
fireSelectionEvent(oldSelection, selection);
}
+ updateAllSelectedState();
+
return changed;
}
@@ -1271,6 +1487,17 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
"Vararg array of itemIds may not be null");
}
}
+
+ private void updateAllSelectedState() {
+ if (getState().allSelected != selection.size() >= selectionLimit) {
+ getState().allSelected = selection.size() >= selectionLimit;
+ }
+ }
+
+ @Override
+ protected MultiSelectionModelState getState() {
+ return (MultiSelectionModelState) super.getState();
+ }
}
/**
@@ -1415,39 +1642,174 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
- * Callback interface for generating custom style names for data rows
+ * A callback interface for generating custom style names for Grid rows.
*
* @see Grid#setRowStyleGenerator(RowStyleGenerator)
*/
public interface RowStyleGenerator extends Serializable {
/**
- * Called by Grid to generate a style name for a row
+ * Called by Grid to generate a style name for a row.
*
- * @param rowReference
- * The row to generate a style for
+ * @param row
+ * the row to generate a style for
* @return the style name to add to this row, or {@code null} to not set
* any style
*/
- public String getStyle(RowReference rowReference);
+ public String getStyle(RowReference row);
}
/**
- * Callback interface for generating custom style names for cells
+ * A callback interface for generating custom style names for Grid cells.
*
* @see Grid#setCellStyleGenerator(CellStyleGenerator)
*/
public interface CellStyleGenerator extends Serializable {
/**
- * Called by Grid to generate a style name for a column
+ * Called by Grid to generate a style name for a column.
*
- * @param cellReference
- * The cell to generate a style for
+ * @param cell
+ * the cell to generate a style for
* @return the style name to add to this cell, or {@code null} to not
* set any style
*/
- public String getStyle(CellReference cellReference);
+ public String getStyle(CellReference cell);
+ }
+
+ /**
+ * A callback interface for generating optional descriptions (tooltips) for
+ * Grid rows. If a description is generated for a row, it is used for all
+ * the cells in the row for which a {@link CellDescriptionGenerator cell
+ * description} is not generated.
+ *
+ * @see Grid#setRowDescriptionGenerator(CellDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public interface RowDescriptionGenerator extends Serializable {
+
+ /**
+ * Called by Grid to generate a description (tooltip) for a row. The
+ * description may contain HTML which is rendered directly; if this is
+ * not desired the returned string must be escaped by the implementing
+ * method.
+ *
+ * @param row
+ * the row to generate a description for
+ * @return the row description or {@code null} for no description
+ */
+ public String getDescription(RowReference row);
+ }
+
+ /**
+ * A callback interface for generating optional descriptions (tooltips) for
+ * Grid cells. If a cell has both a {@link RowDescriptionGenerator row
+ * description} and a cell description, the latter has precedence.
+ *
+ * @see Grid#setCellDescriptionGenerator(CellDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public interface CellDescriptionGenerator extends Serializable {
+
+ /**
+ * Called by Grid to generate a description (tooltip) for a cell. The
+ * description may contain HTML which is rendered directly; if this is
+ * not desired the returned string must be escaped by the implementing
+ * method.
+ *
+ * @param cell
+ * the cell to generate a description for
+ * @return the cell description or {@code null} for no description
+ */
+ public String getDescription(CellReference cell);
+ }
+
+ /**
+ * Class for generating all row and cell related data for the essential
+ * parts of Grid.
+ */
+ private class RowDataGenerator implements DataGenerator {
+
+ private void put(String key, String value, JsonObject object) {
+ if (value != null && !value.isEmpty()) {
+ object.put(key, value);
+ }
+ }
+
+ @Override
+ public void generateData(Object itemId, Item item, JsonObject rowData) {
+ RowReference row = new RowReference(Grid.this);
+ row.set(itemId);
+
+ if (rowStyleGenerator != null) {
+ String style = rowStyleGenerator.getStyle(row);
+ put(GridState.JSONKEY_ROWSTYLE, style, rowData);
+ }
+
+ if (rowDescriptionGenerator != null) {
+ String description = rowDescriptionGenerator
+ .getDescription(row);
+ put(GridState.JSONKEY_ROWDESCRIPTION, description, rowData);
+
+ }
+
+ JsonObject cellStyles = Json.createObject();
+ JsonObject cellData = Json.createObject();
+ JsonObject cellDescriptions = Json.createObject();
+
+ CellReference cell = new CellReference(row);
+
+ for (Column column : getColumns()) {
+ cell.set(column.getPropertyId());
+
+ writeData(cell, cellData);
+ writeStyles(cell, cellStyles);
+ writeDescriptions(cell, cellDescriptions);
+ }
+
+ if (cellDescriptionGenerator != null
+ && cellDescriptions.keys().length > 0) {
+ rowData.put(GridState.JSONKEY_CELLDESCRIPTION, cellDescriptions);
+ }
+
+ if (cellStyleGenerator != null && cellStyles.keys().length > 0) {
+ rowData.put(GridState.JSONKEY_CELLSTYLES, cellStyles);
+ }
+
+ rowData.put(GridState.JSONKEY_DATA, cellData);
+ }
+
+ private void writeStyles(CellReference cell, JsonObject styles) {
+ if (cellStyleGenerator != null) {
+ String style = cellStyleGenerator.getStyle(cell);
+ put(columnKeys.key(cell.getPropertyId()), style, styles);
+ }
+ }
+
+ private void writeDescriptions(CellReference cell,
+ JsonObject descriptions) {
+ if (cellDescriptionGenerator != null) {
+ String description = cellDescriptionGenerator
+ .getDescription(cell);
+ put(columnKeys.key(cell.getPropertyId()), description,
+ descriptions);
+ }
+ }
+
+ private void writeData(CellReference cell, JsonObject data) {
+ Column column = getColumn(cell.getPropertyId());
+ Converter<?, ?> converter = column.getConverter();
+ Renderer<?> renderer = column.getRenderer();
+
+ Item item = cell.getItem();
+ Object modelValue = item.getItemProperty(cell.getPropertyId())
+ .getValue();
+
+ data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer
+ .encodeValue(modelValue, renderer, converter, getLocale()));
+ }
}
/**
@@ -3281,7 +3643,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* currently extends the AbstractExtension superclass, but this fact should
* be regarded as an implementation detail and subject to change in a future
* major or minor Vaadin revision.
- *
+ *
* @param <T>
* the type this renderer knows how to present
*/
@@ -3354,7 +3716,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* is desired. For instance, a {@code Renderer<Date>} could first turn a
* date value into a formatted string and return
* {@code encode(dateString, String.class)}.
- *
+ *
* @param value
* the value to be encoded
* @param type
@@ -3365,11 +3727,79 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
return JsonCodec.encode(value, null, type,
getUI().getConnectorTracker()).getEncodedValue();
}
+
+ /**
+ * Converts and encodes the given data model property value using the
+ * given converter and renderer. This method is public only for testing
+ * purposes.
+ *
+ * @param renderer
+ * the renderer to use
+ * @param converter
+ * the converter to use
+ * @param modelValue
+ * the value to convert and encode
+ * @param locale
+ * the locale to use in conversion
+ * @return an encoded value ready to be sent to the client
+ */
+ public static <T> JsonValue encodeValue(Object modelValue,
+ Renderer<T> renderer, Converter<?, ?> converter, Locale locale) {
+ Class<T> presentationType = renderer.getPresentationType();
+ T presentationValue;
+
+ if (converter == null) {
+ try {
+ presentationValue = presentationType.cast(modelValue);
+ } catch (ClassCastException e) {
+ if (presentationType == String.class) {
+ // If there is no converter, just fallback to using
+ // toString(). modelValue can't be null as
+ // Class.cast(null) will always succeed
+ presentationValue = (T) modelValue.toString();
+ } else {
+ throw new Converter.ConversionException(
+ "Unable to convert value of type "
+ + modelValue.getClass().getName()
+ + " to presentation type "
+ + presentationType.getName()
+ + ". No converter is set and the types are not compatible.");
+ }
+ }
+ } else {
+ assert presentationType.isAssignableFrom(converter
+ .getPresentationType());
+ @SuppressWarnings("unchecked")
+ Converter<T, Object> safeConverter = (Converter<T, Object>) converter;
+ presentationValue = safeConverter
+ .convertToPresentation(modelValue,
+ safeConverter.getPresentationType(), locale);
+ }
+
+ JsonValue encodedValue;
+ try {
+ encodedValue = renderer.encode(presentationValue);
+ } catch (Exception e) {
+ getLogger().log(Level.SEVERE, "Unable to encode data", e);
+ encodedValue = renderer.encode(null);
+ }
+
+ return encodedValue;
+ }
+
+ private static Logger getLogger() {
+ return Logger.getLogger(AbstractRenderer.class.getName());
+ }
+
}
/**
* An abstract base class for server-side Grid extensions.
- *
+ * <p>
+ * Note: If the extension is an instance of {@link DataGenerator} it will
+ * automatically register itself to {@link RpcDataProviderExtension} of
+ * extended Grid. On remove this registration is automatically removed.
+ *
* @since 7.5
*/
public static abstract class AbstractGridExtension extends
@@ -3384,7 +3814,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
/**
* Constructs a new Grid extension and extends given Grid.
- *
+ *
* @param grid
* a grid instance
*/
@@ -3393,6 +3823,26 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
extend(grid);
}
+ @Override
+ protected void extend(AbstractClientConnector target) {
+ super.extend(target);
+
+ if (this instanceof DataGenerator) {
+ getParentGrid().datasourceExtension
+ .addDataGenerator((DataGenerator) this);
+ }
+ }
+
+ @Override
+ public void remove() {
+ if (this instanceof DataGenerator) {
+ getParentGrid().datasourceExtension
+ .removeDataGenerator((DataGenerator) this);
+ }
+
+ super.remove();
+ }
+
/**
* Gets the item id for a row key.
* <p>
@@ -3405,7 +3855,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* @return the item id corresponding to {@code key}
*/
protected Object getItemId(String rowKey) {
- return getParentGrid().getKeyMapper().getItemId(rowKey);
+ return getParentGrid().getKeyMapper().get(rowKey);
}
/**
@@ -3434,11 +3884,27 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
if (getParent() instanceof Grid) {
Grid grid = (Grid) getParent();
return grid;
+ } else if (getParent() == null) {
+ throw new IllegalStateException(
+ "Renderer is not attached to any parent");
} else {
throw new IllegalStateException(
- "Renderers can be used only with Grid");
+ "Renderers can be used only with Grid. Extended "
+ + getParent().getClass().getSimpleName()
+ + " instead");
}
}
+
+ /**
+ * Resends the row data for given item id to the client.
+ *
+ * @since
+ * @param itemId
+ * row to refresh
+ */
+ protected void refreshRow(Object itemId) {
+ getParentGrid().datasourceExtension.updateRowData(itemId);
+ }
}
/**
@@ -3514,6 +3980,13 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
};
+ private final ItemSetChangeListener editorClosingItemSetListener = new ItemSetChangeListener() {
+ @Override
+ public void containerItemSetChange(ItemSetChangeEvent event) {
+ cancelEditor();
+ }
+ };
+
private RpcDataProviderExtension datasourceExtension;
/**
@@ -3539,6 +4012,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
private CellStyleGenerator cellStyleGenerator;
private RowStyleGenerator rowStyleGenerator;
+ private CellDescriptionGenerator cellDescriptionGenerator;
+ private RowDescriptionGenerator rowDescriptionGenerator;
+
/**
* <code>true</code> if Grid is using the internal IndexedContainer created
* in Grid() constructor, or <code>false</code> if the user has set their
@@ -3628,117 +4104,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
private void initGrid() {
setSelectionMode(getDefaultSelectionMode());
- addSelectionListener(new SelectionListener() {
- @Override
- public void select(SelectionEvent event) {
- if (applyingSelectionFromClient) {
- /*
- * Avoid sending changes back to the client if they
- * originated from the client. Instead, the RPC handler is
- * responsible for keeping track of the resulting selection
- * state and notifying the client if it doens't match the
- * expectation.
- */
- return;
- }
-
- /*
- * The rows are pinned here to ensure that the client gets the
- * correct key from server when the selected row is first
- * loaded.
- *
- * Once the client has gotten info that it is supposed to select
- * a row, it will pin the data from the client side as well and
- * it will be unpinned once it gets deselected. Nothing on the
- * server side should ever unpin anything from KeyMapper.
- * Pinning is mostly a client feature and is only used when
- * selecting something from the server side.
- */
- for (Object addedItemId : event.getAdded()) {
- if (!getKeyMapper().isPinned(addedItemId)) {
- getKeyMapper().pin(addedItemId);
- }
- }
-
- getState().selectedKeys = getKeyMapper().getKeys(
- getSelectedRows());
- }
- });
registerRpc(new GridServerRpc() {
@Override
- public void select(List<String> selection) {
- Collection<Object> receivedSelection = getKeyMapper()
- .getItemIds(selection);
-
- applyingSelectionFromClient = true;
- try {
- SelectionModel selectionModel = getSelectionModel();
- if (selectionModel instanceof SelectionModel.Single
- && selection.size() <= 1) {
- Object select = null;
- if (selection.size() == 1) {
- select = getKeyMapper().getItemId(selection.get(0));
- }
- ((SelectionModel.Single) selectionModel).select(select);
- } else if (selectionModel instanceof SelectionModel.Multi) {
- ((SelectionModel.Multi) selectionModel)
- .setSelected(receivedSelection);
- } else {
- throw new IllegalStateException("SelectionModel "
- + selectionModel.getClass().getSimpleName()
- + " does not support selecting the given "
- + selection.size() + " items.");
- }
- } finally {
- applyingSelectionFromClient = false;
- }
-
- Collection<Object> actualSelection = getSelectedRows();
-
- // Make sure all selected rows are pinned
- for (Object itemId : actualSelection) {
- if (!getKeyMapper().isPinned(itemId)) {
- getKeyMapper().pin(itemId);
- }
- }
-
- // Don't mark as dirty since this might be the expected state
- getState(false).selectedKeys = getKeyMapper().getKeys(
- actualSelection);
-
- JsonObject diffState = getUI().getConnectorTracker()
- .getDiffState(Grid.this);
-
- final String diffstateKey = "selectedKeys";
-
- assert diffState.hasKey(diffstateKey) : "Field name has changed";
-
- if (receivedSelection.equals(actualSelection)) {
- /*
- * We ended up with the same selection state that the client
- * sent us. There's nothing to send back to the client, just
- * update the diffstate so subsequent changes will be
- * detected.
- */
- JsonArray diffSelected = Json.createArray();
- for (String rowKey : getState(false).selectedKeys) {
- diffSelected.set(diffSelected.length(), rowKey);
- }
- diffState.put(diffstateKey, diffSelected);
- } else {
- /*
- * Actual selection is not what the client expects. Make
- * sure the client gets a state change event by clearing the
- * diffstate and marking as dirty
- */
- diffState.remove(diffstateKey);
- markAsDirty();
- }
- }
-
- @Override
public void sort(String[] columnIds, SortDirection[] directions,
boolean userOriginated) {
assert columnIds.length == directions.length;
@@ -3767,16 +4136,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
@Override
- public void selectAll() {
- assert getSelectionModel() instanceof SelectionModel.Multi : "Not a multi selection model!";
-
- ((SelectionModel.Multi) getSelectionModel()).selectAll();
- }
-
- @Override
public void itemClick(String rowKey, String columnId,
MouseEventDetails details) {
- Object itemId = getKeyMapper().getItemId(rowKey);
+ Object itemId = getKeyMapper().get(rowKey);
Item item = datasource.getItem(itemId);
Object propertyId = getPropertyIdByColumnId(columnId);
fireEvent(new ItemClickEvent(Grid.this, item, itemId,
@@ -3858,10 +4220,21 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
@Override
- public void sendDetailsComponents(int fetchId) {
- getRpcProxy(GridClientRpc.class).setDetailsConnectorChanges(
- detailComponentManager.getAndResetConnectorChanges(),
- fetchId);
+ public void editorOpen(String rowKey) {
+ fireEvent(new EditorOpenEvent(Grid.this, getKeyMapper().get(
+ rowKey)));
+ }
+
+ @Override
+ public void editorMove(String rowKey) {
+ fireEvent(new EditorMoveEvent(Grid.this, getKeyMapper().get(
+ rowKey)));
+ }
+
+ @Override
+ public void editorClose(String rowKey) {
+ fireEvent(new EditorCloseEvent(Grid.this, getKeyMapper().get(
+ rowKey)));
}
});
@@ -3869,28 +4242,37 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
@Override
public void bind(int rowIndex) {
- Exception exception = null;
try {
Object id = getContainerDataSource().getIdByIndex(rowIndex);
- if (editedItemId == null) {
- editedItemId = id;
- }
- if (editedItemId.equals(id)) {
- doEditItem();
+ final boolean opening = editedItemId == null;
+
+ final boolean moving = !opening && !editedItemId.equals(id);
+
+ final boolean allowMove = !isEditorBuffered()
+ && getEditorFieldGroup().isValid();
+
+ if (opening || !moving || allowMove) {
+ doBind(id);
+ } else {
+ failBind(null);
}
} catch (Exception e) {
- exception = e;
+ failBind(e);
}
+ }
- if (exception != null) {
- handleError(exception);
- doCancelEditor();
- getEditorRpc().confirmBind(false);
- } else {
- doEditItem();
- getEditorRpc().confirmBind(true);
+ private void doBind(Object id) {
+ editedItemId = id;
+ doEditItem();
+ getEditorRpc().confirmBind(true);
+ }
+
+ private void failBind(Exception e) {
+ if (e != null) {
+ handleError(e);
}
+ getEditorRpc().confirmBind(false);
}
@Override
@@ -3999,10 +4381,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
removeExtension(datasourceExtension);
}
- datasource = container;
-
resetEditor();
+ datasource = container;
+
//
// Adjust sort order
//
@@ -4031,7 +4413,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
datasourceExtension = new RpcDataProviderExtension(container);
- datasourceExtension.extend(this, columnKeys);
+ datasourceExtension.extend(this);
+ datasourceExtension.addDataGenerator(new RowDataGenerator());
detailComponentManager = datasourceExtension
.getDetailComponentManager();
@@ -4049,6 +4432,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
((PropertySetChangeNotifier) datasource)
.addPropertySetChangeListener(propertyListener);
}
+
/*
* activeRowHandler will be updated by the client-side request that
* occurs on container change - no need to actively re-insert any
@@ -4643,25 +5027,11 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
if (this.selectionModel != selectionModel) {
// this.selectionModel is null on init
if (this.selectionModel != null) {
- this.selectionModel.reset();
- this.selectionModel.setGrid(null);
+ this.selectionModel.remove();
}
this.selectionModel = selectionModel;
- this.selectionModel.setGrid(this);
- this.selectionModel.reset();
-
- if (selectionModel.getClass().equals(SingleSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.SINGLE;
- } else if (selectionModel.getClass().equals(
- MultiSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.MULTI;
- } else if (selectionModel.getClass().equals(NoSelectionModel.class)) {
- getState().selectionMode = SharedSelectionMode.NONE;
- } else {
- throw new UnsupportedOperationException("Grid currently "
- + "supports only its own bundled selection models");
- }
+ selectionModel.setGrid(this);
}
}
@@ -4928,7 +5298,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*
* @return the key mapper being used by the data source
*/
- DataProviderKeyMapper getKeyMapper() {
+ KeyMapper<Object> getKeyMapper() {
return datasourceExtension.getKeyMapper();
}
@@ -5489,6 +5859,73 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
+ * Sets the {@code CellDescriptionGenerator} instance for generating
+ * optional descriptions (tooltips) for individual Grid cells. If a
+ * {@link RowDescriptionGenerator} is also set, the row description it
+ * generates is displayed for cells for which {@code generator} returns
+ * null.
+ *
+ * @param generator
+ * the description generator to use or {@code null} to remove a
+ * previously set generator if any
+ *
+ * @see #setRowDescriptionGenerator(RowDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public void setCellDescriptionGenerator(CellDescriptionGenerator generator) {
+ cellDescriptionGenerator = generator;
+ getState().hasDescriptions = (generator != null || rowDescriptionGenerator != null);
+ datasourceExtension.refreshCache();
+ }
+
+ /**
+ * Returns the {@code CellDescriptionGenerator} instance used to generate
+ * descriptions (tooltips) for Grid cells.
+ *
+ * @return the description generator or {@code null} if no generator is set
+ *
+ * @since 7.6
+ */
+ public CellDescriptionGenerator getCellDescriptionGenerator() {
+ return cellDescriptionGenerator;
+ }
+
+ /**
+ * Sets the {@code RowDescriptionGenerator} instance for generating optional
+ * descriptions (tooltips) for Grid rows. If a
+ * {@link CellDescriptionGenerator} is also set, the row description
+ * generated by {@code generator} is used for cells for which the cell
+ * description generator returns null.
+ *
+ *
+ * @param generator
+ * the description generator to use or {@code null} to remove a
+ * previously set generator if any
+ *
+ * @see #setCellDescriptionGenerator(CellDescriptionGenerator)
+ *
+ * @since 7.6
+ */
+ public void setRowDescriptionGenerator(RowDescriptionGenerator generator) {
+ rowDescriptionGenerator = generator;
+ getState().hasDescriptions = (generator != null || cellDescriptionGenerator != null);
+ datasourceExtension.refreshCache();
+ }
+
+ /**
+ * Returns the {@code RowDescriptionGenerator} instance used to generate
+ * descriptions (tooltips) for Grid rows
+ *
+ * @return the description generator or {@code} null if no generator is set
+ *
+ * @since 7.6
+ */
+ public RowDescriptionGenerator getRowDescriptionGenerator() {
+ return rowDescriptionGenerator;
+ }
+
+ /**
* Sets the style generator that is used for generating styles for cells
*
* @param cellStyleGenerator
@@ -5497,8 +5934,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
public void setCellStyleGenerator(CellStyleGenerator cellStyleGenerator) {
this.cellStyleGenerator = cellStyleGenerator;
- getState().hasCellStyleGenerator = (cellStyleGenerator != null);
-
datasourceExtension.refreshCache();
}
@@ -5521,8 +5956,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
*/
public void setRowStyleGenerator(RowStyleGenerator rowStyleGenerator) {
this.rowStyleGenerator = rowStyleGenerator;
- getState().hasRowStyleGenerator = (rowStyleGenerator != null);
-
datasourceExtension.refreshCache();
}
@@ -5732,10 +6165,14 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* Opens the editor interface for the provided item. Scrolls the Grid to
* bring the item to view if it is not already visible.
*
+ * Note that any cell content rendered by a WidgetRenderer will not be
+ * visible in the editor row.
+ *
* @param itemId
* the id of the item to edit
* @throws IllegalStateException
- * if the editor is not enabled or already editing an item
+ * if the editor is not enabled or already editing an item in
+ * buffered mode
* @throws IllegalArgumentException
* if the {@code itemId} is not in the backing container
* @see #setEditorEnabled(boolean)
@@ -5744,8 +6181,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
IllegalArgumentException {
if (!isEditorEnabled()) {
throw new IllegalStateException("Item editor is not enabled");
- } else if (editedItemId != null) {
- throw new IllegalStateException("Editing item + " + itemId
+ } else if (isEditorBuffered() && editedItemId != null) {
+ throw new IllegalStateException("Editing item " + itemId
+ " failed. Item editor is already editing item "
+ editedItemId);
} else if (!getContainerDataSource().containsId(itemId)) {
@@ -5773,6 +6210,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
f.markAsDirtyRecursive();
}
+ if (datasource instanceof ItemSetChangeNotifier) {
+ ((ItemSetChangeNotifier) datasource)
+ .addItemSetChangeListener(editorClosingItemSetListener);
+ }
}
private void setEditorField(Object propertyId, Field<?> field) {
@@ -5822,6 +6263,11 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
editorFieldGroup.discard();
editorFieldGroup.setItemDataSource(null);
+ if (datasource instanceof ItemSetChangeNotifier) {
+ ((ItemSetChangeNotifier) datasource)
+ .removeItemSetChangeListener(editorClosingItemSetListener);
+ }
+
// Mark Grid as dirty so the client side gets to know that the editors
// are no longer attached
markAsDirty();
@@ -5971,6 +6417,70 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
return getState(false).editorCancelCaption;
}
+ /**
+ * Add an editor event listener
+ *
+ * @param listener
+ * the event listener object to add
+ */
+ public void addEditorListener(EditorListener listener) {
+ addListener(GridConstants.EDITOR_OPEN_EVENT_ID, EditorOpenEvent.class,
+ listener, EditorListener.EDITOR_OPEN_METHOD);
+ addListener(GridConstants.EDITOR_MOVE_EVENT_ID, EditorMoveEvent.class,
+ listener, EditorListener.EDITOR_MOVE_METHOD);
+ addListener(GridConstants.EDITOR_CLOSE_EVENT_ID,
+ EditorCloseEvent.class, listener,
+ EditorListener.EDITOR_CLOSE_METHOD);
+ }
+
+ /**
+ * Remove an editor event listener
+ *
+ * @param listener
+ * the event listener object to remove
+ */
+ public void removeEditorListener(EditorListener listener) {
+ removeListener(GridConstants.EDITOR_OPEN_EVENT_ID,
+ EditorOpenEvent.class, listener);
+ removeListener(GridConstants.EDITOR_MOVE_EVENT_ID,
+ EditorMoveEvent.class, listener);
+ removeListener(GridConstants.EDITOR_CLOSE_EVENT_ID,
+ EditorCloseEvent.class, listener);
+ }
+
+ /**
+ * Sets the buffered editor mode. The default mode is buffered (
+ * <code>true</code>).
+ *
+ * @since 7.6
+ * @param editorBuffered
+ * <code>true</code> to enable buffered editor,
+ * <code>false</code> to disable it
+ * @throws IllegalStateException
+ * If editor is active while attempting to change the buffered
+ * mode.
+ */
+ public void setEditorBuffered(boolean editorBuffered)
+ throws IllegalStateException {
+ if (isEditorActive()) {
+ throw new IllegalStateException(
+ "Can't change editor unbuffered mode while editor is active.");
+ }
+ getState().editorBuffered = editorBuffered;
+ editorFieldGroup.setBuffered(editorBuffered);
+ }
+
+ /**
+ * Gets the buffered editor mode.
+ *
+ * @since 7.6
+ * @return <code>true</code> if buffered editor is enabled,
+ * <code>false</code> otherwise
+ */
+ public boolean isEditorBuffered() {
+ return getState(false).editorBuffered;
+ }
+
@Override
public void addItemClickListener(ItemClickListener listener) {
addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
@@ -6063,8 +6573,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
this.detailsGenerator = detailsGenerator;
datasourceExtension.refreshDetails();
- getRpcProxy(GridClientRpc.class).setDetailsConnectorChanges(
- detailComponentManager.getAndResetConnectorChanges(), -1);
}
/**
@@ -6088,6 +6596,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* to hide them
*/
public void setDetailsVisible(Object itemId, boolean visible) {
+ if (DetailsGenerator.NULL.equals(detailsGenerator)) {
+ return;
+ }
datasourceExtension.setDetailsVisible(itemId, visible);
}
@@ -6265,6 +6776,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
result.add("footer-visible");
result.add("editor-error-handler");
result.add("height-mode");
+
return result;
}
}
diff --git a/server/src/com/vaadin/ui/HorizontalLayout.java b/server/src/com/vaadin/ui/HorizontalLayout.java
index 54569570b9..616fa09225 100644
--- a/server/src/com/vaadin/ui/HorizontalLayout.java
+++ b/server/src/com/vaadin/ui/HorizontalLayout.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.ui;
+import com.vaadin.shared.ui.orderedlayout.HorizontalLayoutState;
+
/**
* Horizontal layout
*
@@ -48,4 +50,9 @@ public class HorizontalLayout extends AbstractOrderedLayout {
addComponents(children);
}
+ @Override
+ protected HorizontalLayoutState getState() {
+ return (HorizontalLayoutState) super.getState();
+ }
+
}
diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java
index 42c4beab6c..10d1c45ab6 100644
--- a/server/src/com/vaadin/ui/Table.java
+++ b/server/src/com/vaadin/ui/Table.java
@@ -69,6 +69,7 @@ import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.ui.declarative.DesignException;
+import com.vaadin.util.ReflectTools;
/**
* <p>
@@ -1310,6 +1311,8 @@ public class Table extends AbstractSelect implements Action.Container,
* the desired collapsedness.
* @throws IllegalStateException
* if column collapsing is not allowed
+ * @throws IllegalArgumentException
+ * if the property id does not exist
*/
public void setColumnCollapsed(Object propertyId, boolean collapsed)
throws IllegalStateException {
@@ -1319,11 +1322,20 @@ public class Table extends AbstractSelect implements Action.Container,
if (collapsed && noncollapsibleColumns.contains(propertyId)) {
throw new IllegalStateException("The column is noncollapsible!");
}
+ if (!getContainerPropertyIds().contains(propertyId)
+ && !columnGenerators.containsKey(propertyId)) {
+ throw new IllegalArgumentException("Property '" + propertyId
+ + "' was not found in the container");
+ }
if (collapsed) {
- collapsedColumns.add(propertyId);
+ if (collapsedColumns.add(propertyId)) {
+ fireColumnCollapseEvent(propertyId);
+ }
} else {
- collapsedColumns.remove(propertyId);
+ if (collapsedColumns.remove(propertyId)) {
+ fireColumnCollapseEvent(propertyId);
+ }
}
// Assures the visual refresh
@@ -3182,6 +3194,10 @@ public class Table extends AbstractSelect implements Action.Container,
}
}
+ private void fireColumnCollapseEvent(Object propertyId) {
+ fireEvent(new ColumnCollapseEvent(this, propertyId));
+ }
+
private void fireColumnResizeEvent(Object propertyId, int previousWidth,
int currentWidth) {
/*
@@ -5742,6 +5758,53 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
+ * This event is fired when the collapse state of a column changes
+ */
+ public static class ColumnCollapseEvent extends Component.Event {
+
+ public static final Method METHOD = ReflectTools.findMethod(
+ ColumnCollapseListener.class, "columnCollapseStateChange",
+ ColumnCollapseEvent.class);
+ private Object propertyId;
+
+ /**
+ * Constructor
+ *
+ * @param source
+ * The source of the event
+ * @param propertyId
+ * The id of the column
+ */
+ public ColumnCollapseEvent(Component source, Object propertyId) {
+ super(source);
+ this.propertyId = propertyId;
+ }
+
+ /**
+ * Gets the id of the column whose collapse state changed
+ *
+ * @return the property id of the column
+ */
+ public Object getPropertyId() {
+ return propertyId;
+ }
+ }
+
+ /**
+ * Interface for listening to column collapse events.
+ */
+ public interface ColumnCollapseListener extends Serializable {
+
+ /**
+ * This method is triggered when the collapse state for a column has
+ * changed
+ *
+ * @param event
+ */
+ public void columnCollapseStateChange(ColumnCollapseEvent event);
+ }
+
+ /**
* Adds a column reorder listener to the Table. A column reorder listener is
* called when a user reorders columns.
*
@@ -5783,6 +5846,29 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
+ * Adds a column collapse listener to the Table. A column collapse listener
+ * is called when the collapsed state of a column changes.
+ *
+ * @param listener
+ * The listener to attach
+ */
+ public void addColumnCollapseListener(ColumnCollapseListener listener) {
+ addListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID,
+ ColumnCollapseEvent.class, listener, ColumnCollapseEvent.METHOD);
+ }
+
+ /**
+ * Removes a column reorder listener from the Table.
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeColumnCollapseListener(ColumnCollapseListener listener) {
+ removeListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID,
+ ColumnCollapseEvent.class, listener);
+ }
+
+ /**
* Set the item description generator which generates tooltips for cells and
* rows in the Table
*
diff --git a/server/src/com/vaadin/ui/VerticalLayout.java b/server/src/com/vaadin/ui/VerticalLayout.java
index 12819e50bc..7002fbc7e6 100644
--- a/server/src/com/vaadin/ui/VerticalLayout.java
+++ b/server/src/com/vaadin/ui/VerticalLayout.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.ui;
+import com.vaadin.shared.ui.orderedlayout.VerticalLayoutState;
+
/**
* Vertical layout
*
@@ -48,4 +50,9 @@ public class VerticalLayout extends AbstractOrderedLayout {
this();
addComponents(children);
}
+
+ @Override
+ protected VerticalLayoutState getState() {
+ return (VerticalLayoutState) super.getState();
+ }
}
diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java
index 61ba5826b8..fd5565f900 100644
--- a/server/src/com/vaadin/ui/Window.java
+++ b/server/src/com/vaadin/ui/Window.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -74,7 +75,7 @@ import com.vaadin.util.ReflectTools;
* @author Vaadin Ltd.
* @since 3.0
*/
-@SuppressWarnings("serial")
+@SuppressWarnings({ "serial", "deprecation" })
public class Window extends Panel implements FocusNotifier, BlurNotifier,
LegacyComponent {
@@ -102,6 +103,11 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
};
/**
+ * Holds registered CloseShortcut instances for query and later removal
+ */
+ private List<CloseShortcut> closeShortcuts = new ArrayList<CloseShortcut>(4);
+
+ /**
* Creates a new, empty window
*/
public Window() {
@@ -130,6 +136,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
super(caption, content);
registerRpc(rpc);
setSizeUndefined();
+ setCloseShortcut(KeyCode.ESCAPE);
}
/* ********************************************************************* */
@@ -828,14 +835,22 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
}
}
- /*
- * Actions
- */
- protected CloseShortcut closeShortcut;
-
/**
- * Makes is possible to close the window by pressing the given
- * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
+ * This is the old way of adding a keyboard shortcut to close a
+ * {@link Window} - to preserve compatibility with existing code under the
+ * new functionality, this method now first removes all registered close
+ * shortcuts, then adds the default ESCAPE shortcut key, and then attempts
+ * to add the shortcut provided as parameters to this method. This method,
+ * and its companion {@link #removeCloseShortcut()}, are now considered
+ * deprecated, as their main function is to preserve exact backwards
+ * compatibility with old code. For all new code, use the new keyboard
+ * shortcuts API: {@link #addCloseShortcut(int,int...)},
+ * {@link #removeCloseShortcut(int,int...)},
+ * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
+ * and {@link #getCloseShortcuts()}.
+ * <p>
+ * Original description: Makes it possible to close the window by pressing
+ * the given {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
* Note that this shortcut only reacts while the window has focus, closing
* itself - if you want to close a window from a UI, use
* {@link UI#addAction(com.vaadin.event.Action)} of the UI instead.
@@ -843,29 +858,137 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
* @param keyCode
* the keycode for invoking the shortcut
* @param modifiers
- * the (optional) modifiers for invoking the shortcut, null for
- * none
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ *
+ * @deprecated Use {@link #addCloseShortcut(int, int...)} instead.
*/
+ @Deprecated
public void setCloseShortcut(int keyCode, int... modifiers) {
- if (closeShortcut != null) {
- removeAction(closeShortcut);
- }
- closeShortcut = new CloseShortcut(this, keyCode, modifiers);
- addAction(closeShortcut);
+ removeCloseShortcut();
+ addCloseShortcut(keyCode, modifiers);
}
/**
- * Removes the keyboard shortcut previously set with
- * {@link #setCloseShortcut(int, int...)}.
+ * Removes all keyboard shortcuts previously set with
+ * {@link #setCloseShortcut(int, int...)} and
+ * {@link #addCloseShortcut(int, int...)}, then adds the default
+ * {@link KeyCode#ESCAPE} shortcut.
+ * <p>
+ * This is the old way of removing the (single) keyboard close shortcut, and
+ * is retained only for exact backwards compatibility. For all new code, use
+ * the new keyboard shortcuts API: {@link #addCloseShortcut(int,int...)},
+ * {@link #removeCloseShortcut(int,int...)},
+ * {@link #removeAllCloseShortcuts()}, {@link #hasCloseShortcut(int,int...)}
+ * and {@link #getCloseShortcuts()}.
+ *
+ * @deprecated Use {@link #removeCloseShortcut(int, int...)} instead.
*/
+ @Deprecated
public void removeCloseShortcut() {
- if (closeShortcut != null) {
- removeAction(closeShortcut);
- closeShortcut = null;
+ for (int i = 0; i < closeShortcuts.size(); ++i) {
+ CloseShortcut sc = closeShortcuts.get(i);
+ removeAction(sc);
+ }
+ closeShortcuts.clear();
+ addCloseShortcut(KeyCode.ESCAPE);
+ }
+
+ /**
+ * Adds a close shortcut - pressing this key while holding down all (if any)
+ * modifiers specified while this Window is in focus will close the Window.
+ *
+ * @since
+ * @param keyCode
+ * the keycode for invoking the shortcut
+ * @param modifiers
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ */
+ public void addCloseShortcut(int keyCode, int... modifiers) {
+
+ // Ignore attempts to re-add existing shortcuts
+ if (hasCloseShortcut(keyCode, modifiers)) {
+ return;
+ }
+
+ // Actually add the shortcut
+ CloseShortcut shortcut = new CloseShortcut(this, keyCode, modifiers);
+ addAction(shortcut);
+ closeShortcuts.add(shortcut);
+ }
+
+ /**
+ * Removes a close shortcut previously added with
+ * {@link #addCloseShortcut(int, int...)}.
+ *
+ * @since
+ * @param keyCode
+ * the keycode for invoking the shortcut
+ * @param modifiers
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ */
+ public void removeCloseShortcut(int keyCode, int... modifiers) {
+ for (CloseShortcut shortcut : closeShortcuts) {
+ if (shortcut.equals(keyCode, modifiers)) {
+ removeAction(shortcut);
+ closeShortcuts.remove(shortcut);
+ return;
+ }
}
}
/**
+ * Removes all close shortcuts. This includes the default ESCAPE shortcut.
+ * It is up to the user to add back any and all keyboard close shortcuts
+ * they may require. For more fine-grained control over shortcuts, use
+ * {@link #removeCloseShortcut(int, int...)}.
+ *
+ * @since
+ */
+ public void removeAllCloseShortcuts() {
+ for (CloseShortcut shortcut : closeShortcuts) {
+ removeAction(shortcut);
+ }
+ closeShortcuts.clear();
+ }
+
+ /**
+ * Checks if a close window shortcut key has already been registered.
+ *
+ * @since
+ * @param keyCode
+ * the keycode for invoking the shortcut
+ * @param modifiers
+ * the (optional) modifiers for invoking the shortcut. Can be set
+ * to null to be explicit about not having modifiers.
+ * @return true, if an exactly matching shortcut has been registered.
+ */
+ public boolean hasCloseShortcut(int keyCode, int... modifiers) {
+ for (CloseShortcut shortcut : closeShortcuts) {
+ if (shortcut.equals(keyCode, modifiers)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an unmodifiable collection of {@link CloseShortcut} objects
+ * currently registered with this {@link Window}. This method is provided
+ * mainly so that users can implement their own serialization routines. To
+ * check if a certain combination of keys has been registered as a close
+ * shortcut, use the {@link #hasCloseShortcut(int, int...)} method instead.
+ *
+ * @since
+ * @return an unmodifiable Collection of CloseShortcut objects.
+ */
+ public Collection<CloseShortcut> getCloseShortcuts() {
+ return Collections.unmodifiableCollection(closeShortcuts);
+ }
+
+ /**
* A {@link ShortcutListener} specifically made to define a keyboard
* shortcut that closes the window.
*
@@ -930,6 +1053,25 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
public void handleAction(Object sender, Object target) {
window.close();
}
+
+ public boolean equals(int keyCode, int... modifiers) {
+ if (keyCode != getKeyCode()) {
+ return false;
+ }
+
+ if (getModifiers() != null) {
+ int[] mods = null;
+ if (modifiers != null) {
+ // Modifiers provided by the parent ShortcutAction class
+ // are guaranteed to be sorted. We still need to sort
+ // the modifiers passed in as argument.
+ mods = Arrays.copyOf(modifiers, modifiers.length);
+ Arrays.sort(mods);
+ }
+ return Arrays.equals(mods, getModifiers());
+ }
+ return true;
+ }
}
/*
@@ -1244,11 +1386,26 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
setPositionX(Integer.parseInt(position[0]));
setPositionY(Integer.parseInt(position[1]));
}
+
+ // Parse shortcuts if defined, otherwise rely on default behavior
if (design.hasAttr("close-shortcut")) {
- ShortcutAction shortcut = DesignAttributeHandler
- .readAttribute("close-shortcut", design.attributes(),
- ShortcutAction.class);
- setCloseShortcut(shortcut.getKeyCode(), shortcut.getModifiers());
+
+ // Parse shortcuts
+ String[] shortcutStrings = DesignAttributeHandler.readAttribute(
+ "close-shortcut", design.attributes(), String.class).split(
+ "\\s+");
+
+ removeAllCloseShortcuts();
+
+ for (String part : shortcutStrings) {
+ if (!part.isEmpty()) {
+ ShortcutAction shortcut = DesignAttributeHandler
+ .getFormatter().parse(part.trim(),
+ ShortcutAction.class);
+ addCloseShortcut(shortcut.getKeyCode(),
+ shortcut.getModifiers());
+ }
+ }
}
}
@@ -1302,19 +1459,24 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
DesignAttributeHandler.writeAttribute("position", design.attributes(),
getPosition(), def.getPosition(), String.class);
- CloseShortcut shortcut = getCloseShortcut();
- if (shortcut != null) {
- // TODO What if several close shortcuts??
-
- CloseShortcut defShortcut = def.getCloseShortcut();
- if (defShortcut == null
- || shortcut.getKeyCode() != defShortcut.getKeyCode()
- || !Arrays.equals(shortcut.getModifiers(),
- defShortcut.getModifiers())) {
- DesignAttributeHandler.writeAttribute("close-shortcut",
- design.attributes(), shortcut, null,
- CloseShortcut.class);
+ // Process keyboard shortcuts
+ if (closeShortcuts.size() == 1 && hasCloseShortcut(KeyCode.ESCAPE)) {
+ // By default, we won't write anything if we're relying on default
+ // shortcut behavior
+ } else {
+ // Dump all close shortcuts to a string...
+ String attrString = "";
+
+ // TODO: add canonical support for array data in XML attributes
+ for (CloseShortcut shortcut : closeShortcuts) {
+ String shortcutString = DesignAttributeHandler.getFormatter()
+ .format(shortcut, CloseShortcut.class);
+ attrString += shortcutString + " ";
}
+
+ // Write everything except the last "," to the design
+ DesignAttributeHandler.writeAttribute("close-shortcut",
+ design.attributes(), attrString.trim(), null, String.class);
}
for (Component c : getAssistiveDescription()) {
@@ -1328,10 +1490,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
return getPositionX() + "," + getPositionY();
}
- private CloseShortcut getCloseShortcut() {
- return closeShortcut;
- }
-
@Override
protected Collection<String> getCustomAttributes() {
Collection<String> result = super.getCustomAttributes();
diff --git a/server/src/com/vaadin/ui/renderers/ImageRenderer.java b/server/src/com/vaadin/ui/renderers/ImageRenderer.java
index 2fb872583e..ad7d5cae2b 100644
--- a/server/src/com/vaadin/ui/renderers/ImageRenderer.java
+++ b/server/src/com/vaadin/ui/renderers/ImageRenderer.java
@@ -58,7 +58,7 @@ public class ImageRenderer extends ClickableRenderer<Resource> {
if (!(resource == null || resource instanceof ExternalResource || resource instanceof ThemeResource)) {
throw new IllegalArgumentException(
"ImageRenderer only supports ExternalResource and ThemeResource ("
- + resource.getClass().getSimpleName() + "given )");
+ + resource.getClass().getSimpleName() + " given)");
}
return encode(ResourceReference.create(resource, this, null),
diff --git a/server/src/com/vaadin/ui/themes/ValoTheme.java b/server/src/com/vaadin/ui/themes/ValoTheme.java
index 1285bf7f67..3a9986c632 100644
--- a/server/src/com/vaadin/ui/themes/ValoTheme.java
+++ b/server/src/com/vaadin/ui/themes/ValoTheme.java
@@ -709,7 +709,7 @@ public class ValoTheme {
* area is scrolled. Suitable with the {@link #PANEL_BORDERLESS} style. Can
* be combined with any other Panel style.
*/
- public static final String PANEL_SCROLL_INDICATOR = "scroll-indicator";
+ public static final String PANEL_SCROLL_INDICATOR = "scroll-divider";
/**
* Inset panel style. Can be combined with any other Panel style.
diff --git a/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java b/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java
index 54cbc5305d..55dccc6455 100644
--- a/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java
+++ b/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java
@@ -11,6 +11,7 @@ import com.vaadin.data.Container;
import com.vaadin.data.Container.Filterable;
import com.vaadin.data.Container.ItemSetChangeEvent;
import com.vaadin.data.Container.ItemSetChangeListener;
+import com.vaadin.data.Container.Ordered;
import com.vaadin.data.Container.Sortable;
import com.vaadin.data.Item;
import com.vaadin.data.util.filter.SimpleStringFilter;
@@ -161,54 +162,54 @@ public abstract class AbstractContainerTestBase extends TestCase {
validateContainer(container, sampleData[0],
sampleData[sampleData.length - 1], sampleData[10], "abc", true,
sampleData.length);
+
+ validateRemovingItems(container);
+ }
+
+ protected void validateRemovingItems(Container container) {
+ int sizeBeforeRemoving = container.size();
+
+ List<Object> itemIdList = new ArrayList<Object>(container.getItemIds());
+ // There should be at least four items in the list
+ Object first = itemIdList.get(0);
+ Object middle = itemIdList.get(2);
+ Object last = itemIdList.get(itemIdList.size() - 1);
+
+ container.removeItem(first);
+ container.removeItem(middle); // Middle now that first has been removed
+ container.removeItem(last);
+
+ assertEquals(sizeBeforeRemoving - 3, container.size());
+
+ container.removeAllItems();
+
+ assertEquals(0, container.size());
}
protected void testContainerOrdered(Container.Ordered container) {
+ // addItem with empty container
Object id = container.addItem();
- assertNotNull(id);
+ assertOrderedContents(container, id);
Item item = container.getItem(id);
assertNotNull(item);
- assertEquals(id, container.firstItemId());
- assertEquals(id, container.lastItemId());
-
- // isFirstId
- assertTrue(container.isFirstId(id));
- assertTrue(container.isFirstId(container.firstItemId()));
- // isLastId
- assertTrue(container.isLastId(id));
- assertTrue(container.isLastId(container.lastItemId()));
+ // addItemAfter with empty container
+ container.removeAllItems();
+ assertOrderedContents(container);
+ id = container.addItemAfter(null);
+ assertOrderedContents(container, id);
+ item = container.getItem(id);
+ assertNotNull(item);
// Add a new item before the first
// addItemAfter
Object newFirstId = container.addItemAfter(null);
- assertNotNull(newFirstId);
- assertNotNull(container.getItem(newFirstId));
-
- // isFirstId
- assertTrue(container.isFirstId(newFirstId));
- assertTrue(container.isFirstId(container.firstItemId()));
- // isLastId
- assertTrue(container.isLastId(id));
- assertTrue(container.isLastId(container.lastItemId()));
-
- // nextItemId
- assertEquals(id, container.nextItemId(newFirstId));
- assertNull(container.nextItemId(id));
- assertNull(container.nextItemId("not-in-container"));
-
- // prevItemId
- assertEquals(newFirstId, container.prevItemId(id));
- assertNull(container.prevItemId(newFirstId));
- assertNull(container.prevItemId("not-in-container"));
+ assertOrderedContents(container, newFirstId, id);
// addItemAfter(Object)
Object newSecondItemId = container.addItemAfter(newFirstId);
// order is now: newFirstId, newSecondItemId, id
- assertNotNull(newSecondItemId);
- assertNotNull(container.getItem(newSecondItemId));
- assertEquals(id, container.nextItemId(newSecondItemId));
- assertEquals(newFirstId, container.prevItemId(newSecondItemId));
+ assertOrderedContents(container, newFirstId, newSecondItemId, id);
// addItemAfter(Object,Object)
String fourthId = "id of the fourth item";
@@ -216,8 +217,8 @@ public abstract class AbstractContainerTestBase extends TestCase {
// order is now: newFirstId, fourthId, newSecondItemId, id
assertNotNull(fourth);
assertEquals(fourth, container.getItem(fourthId));
- assertEquals(newSecondItemId, container.nextItemId(fourthId));
- assertEquals(newFirstId, container.prevItemId(fourthId));
+ assertOrderedContents(container, newFirstId, fourthId, newSecondItemId,
+ id);
// addItemAfter(Object,Object)
Object fifthId = new Object();
@@ -225,8 +226,86 @@ public abstract class AbstractContainerTestBase extends TestCase {
// order is now: fifthId, newFirstId, fourthId, newSecondItemId, id
assertNotNull(fifth);
assertEquals(fifth, container.getItem(fifthId));
- assertEquals(newFirstId, container.nextItemId(fifthId));
- assertNull(container.prevItemId(fifthId));
+ assertOrderedContents(container, fifthId, newFirstId, fourthId,
+ newSecondItemId, id);
+
+ // addItemAfter(Object,Object)
+ Object sixthId = new Object();
+ Item sixth = container.addItemAfter(id, sixthId);
+ // order is now: fifthId, newFirstId, fourthId, newSecondItemId, id,
+ // sixthId
+ assertNotNull(sixth);
+ assertEquals(sixth, container.getItem(sixthId));
+ assertOrderedContents(container, fifthId, newFirstId, fourthId,
+ newSecondItemId, id, sixthId);
+
+ // Test order after removing first item 'fifthId'
+ container.removeItem(fifthId);
+ // order is now: newFirstId, fourthId, newSecondItemId, id, sixthId
+ assertOrderedContents(container, newFirstId, fourthId, newSecondItemId,
+ id, sixthId);
+
+ // Test order after removing last item 'sixthId'
+ container.removeItem(sixthId);
+ // order is now: newFirstId, fourthId, newSecondItemId, id
+ assertOrderedContents(container, newFirstId, fourthId, newSecondItemId,
+ id);
+
+ // Test order after removing item from the middle 'fourthId'
+ container.removeItem(fourthId);
+ // order is now: newFirstId, newSecondItemId, id
+ assertOrderedContents(container, newFirstId, newSecondItemId, id);
+
+ // Delete remaining items
+ container.removeItem(newFirstId);
+ container.removeItem(newSecondItemId);
+ container.removeItem(id);
+ assertOrderedContents(container);
+
+ Object finalItem = container.addItem();
+ assertOrderedContents(container, finalItem);
+ }
+
+ private void assertOrderedContents(Ordered container, Object... ids) {
+ assertEquals(ids.length, container.size());
+ for (int i = 0; i < ids.length - 1; i++) {
+ assertNotNull("The item id should not be null", ids[i]);
+ }
+ if (ids.length == 0) {
+ assertNull("The first id is wrong", container.firstItemId());
+ assertNull("The last id is wrong", container.lastItemId());
+ return;
+ }
+
+ assertEquals("The first id is wrong", ids[0], container.firstItemId());
+ assertEquals("The last id is wrong", ids[ids.length - 1],
+ container.lastItemId());
+
+ // isFirstId & isLastId
+ assertTrue(container.isFirstId(container.firstItemId()));
+ assertTrue(container.isLastId(container.lastItemId()));
+
+ // nextId
+ Object ref = container.firstItemId();
+ for (int i = 1; i < ids.length; i++) {
+ Object next = container.nextItemId(ref);
+ assertEquals("The id after " + ref + " is wrong", ids[i], next);
+ ref = next;
+ }
+ assertNull("The last id should not have a next id",
+ container.nextItemId(ids[ids.length - 1]));
+ assertNull(container.nextItemId("not-in-container"));
+
+ // prevId
+ ref = container.lastItemId();
+ for (int i = ids.length - 2; i >= 0; i--) {
+ Object prev = container.prevItemId(ref);
+ assertEquals("The id before " + ref + " is wrong", ids[i], prev);
+ ref = prev;
+ }
+ assertNull("The first id should not have a prev id",
+ container.prevItemId(ids[0]));
+ assertNull(container.prevItemId("not-in-container"));
}
diff --git a/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java b/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java
index 3bd00cce3c..9cede77162 100644
--- a/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java
+++ b/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java
@@ -253,4 +253,33 @@ public abstract class AbstractHierarchicalContainerTestBase extends
}
}
+ protected void testRemoveHierarchicalWrapperSubtree(
+ Container.Hierarchical container) {
+ initializeContainer(container);
+
+ // remove root item
+ removeItemRecursively(container, "org");
+
+ int packages = 21 + 3 - 3;
+ int expectedSize = sampleData.length + packages - 1;
+
+ validateContainer(container, "com", "com.vaadin.util.SerializerHelper",
+ "com.vaadin.server.ApplicationResource", "blah", true,
+ expectedSize);
+
+ // rootItemIds
+ Collection<?> rootIds = container.rootItemIds();
+ assertEquals(1, rootIds.size());
+ }
+
+ private void removeItemRecursively(Container.Hierarchical container,
+ Object itemId) {
+ if (container instanceof ContainerHierarchicalWrapper) {
+ ((ContainerHierarchicalWrapper) container)
+ .removeItemRecursively("org");
+ } else {
+ HierarchicalContainer.removeItemRecursively(container, itemId);
+ }
+ }
+
}
diff --git a/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java b/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java
index 2fd21ef118..8e554d5030 100644
--- a/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java
+++ b/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java
@@ -1,6 +1,5 @@
package com.vaadin.data.util;
-import java.util.Collection;
public class ContainerHierarchicalWrapperTest extends
AbstractHierarchicalContainerTestBase {
@@ -20,23 +19,4 @@ public class ContainerHierarchicalWrapperTest extends
new IndexedContainer()));
}
- protected void testRemoveHierarchicalWrapperSubtree(
- ContainerHierarchicalWrapper container) {
- initializeContainer(container);
-
- // remove root item
- container.removeItemRecursively("org");
-
- int packages = 21 + 3 - 3;
- int expectedSize = sampleData.length + packages - 1;
-
- validateContainer(container, "com", "com.vaadin.util.SerializerHelper",
- "com.vaadin.server.ApplicationResource", "blah", true,
- expectedSize);
-
- // rootItemIds
- Collection<?> rootIds = container.rootItemIds();
- assertEquals(1, rootIds.size());
- }
-
}
diff --git a/server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java b/server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java
new file mode 100644
index 0000000000..422e9756f8
--- /dev/null
+++ b/server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java
@@ -0,0 +1,102 @@
+package com.vaadin.data.util;
+
+import java.util.Collection;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+
+public class ContainerOrderedWrapperTest extends AbstractContainerTestBase {
+
+ // This class is needed to get an implementation of container
+ // which is not an implementation of Ordered interface.
+ private class NotOrderedContainer implements Container {
+
+ private IndexedContainer container;
+
+ public NotOrderedContainer() {
+ container = new IndexedContainer();
+ }
+
+ @Override
+ public Item getItem(Object itemId) {
+ return container.getItem(itemId);
+ }
+
+ @Override
+ public Collection<?> getContainerPropertyIds() {
+ return container.getContainerPropertyIds();
+ }
+
+ @Override
+ public Collection<?> getItemIds() {
+ return container.getItemIds();
+ }
+
+ @Override
+ public Property getContainerProperty(Object itemId, Object propertyId) {
+ return container.getContainerProperty(itemId, propertyId);
+ }
+
+ @Override
+ public Class<?> getType(Object propertyId) {
+ return container.getType(propertyId);
+ }
+
+ @Override
+ public int size() {
+ return container.size();
+ }
+
+ @Override
+ public boolean containsId(Object itemId) {
+ return container.containsId(itemId);
+ }
+
+ @Override
+ public Item addItem(Object itemId) throws UnsupportedOperationException {
+ return container.addItem(itemId);
+ }
+
+ @Override
+ public Object addItem() throws UnsupportedOperationException {
+ return container.addItem();
+ }
+
+ @Override
+ public boolean removeItem(Object itemId)
+ throws UnsupportedOperationException {
+ return container.removeItem(itemId);
+ }
+
+ @Override
+ public boolean addContainerProperty(Object propertyId, Class<?> type,
+ Object defaultValue) throws UnsupportedOperationException {
+ return container.addContainerProperty(propertyId, type,
+ defaultValue);
+ }
+
+ @Override
+ public boolean removeContainerProperty(Object propertyId)
+ throws UnsupportedOperationException {
+ return container.removeContainerProperty(propertyId);
+ }
+
+ @Override
+ public boolean removeAllItems() throws UnsupportedOperationException {
+ return container.removeAllItems();
+ }
+
+ }
+
+ public void testBasicOperations() {
+ testBasicContainerOperations(new ContainerOrderedWrapper(
+ new NotOrderedContainer()));
+ }
+
+ public void testOrdered() {
+ testContainerOrdered(new ContainerOrderedWrapper(
+ new NotOrderedContainer()));
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java b/server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java
new file mode 100644
index 0000000000..7ecf59c309
--- /dev/null
+++ b/server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java
@@ -0,0 +1,27 @@
+package com.vaadin.data.util;
+
+public class HierarchicalContainerOrderedWrapperTest extends
+ AbstractHierarchicalContainerTestBase {
+
+ private HierarchicalContainerOrderedWrapper createContainer() {
+ return new HierarchicalContainerOrderedWrapper(
+ new ContainerHierarchicalWrapper(new IndexedContainer()));
+ }
+
+ public void testBasicOperations() {
+ testBasicContainerOperations(createContainer());
+ }
+
+ public void testHierarchicalContainer() {
+ testHierarchicalContainer(createContainer());
+ }
+
+ public void testContainerOrdered() {
+ testContainerOrdered(createContainer());
+ }
+
+ public void testRemoveSubtree() {
+ testRemoveHierarchicalWrapperSubtree(createContainer());
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java
index 2cb4c3bf4d..286163541e 100644
--- a/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java
+++ b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java
@@ -15,50 +15,136 @@
*/
package com.vaadin.server.communication;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mockito;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.StreamVariable;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.ui.ConnectorTracker;
+import com.vaadin.ui.UI;
-/**
- * Tests whether we get infinite loop if InputStream is already read (#10096)
- */
public class FileUploadHandlerTest {
private FileUploadHandler handler;
- private VaadinRequest request;
+ @Mock private VaadinResponse response;
+ @Mock private StreamVariable streamVariable;
+ @Mock private ClientConnector clientConnector;
+ @Mock private VaadinRequest request;
+ @Mock private UI ui;
+ @Mock private ConnectorTracker connectorTracker;
+ @Mock private VaadinSession session;
+ @Mock private OutputStream responseOutput;
+
+ private int uiId = 123;
+ private final String connectorId = "connectorId";
+ private final String variableName = "name";
+ private final String expectedSecurityKey = "key";
@Before
public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
handler = new FileUploadHandler();
- InputStream inputStream = new InputStream() {
- private int counter = 0;
+
+ mockRequest();
+ mockConnectorTracker();
+ mockUi();
+
+ when(clientConnector.isConnectorEnabled()).thenReturn(true);
+ when(streamVariable.getOutputStream()).thenReturn(mock(OutputStream.class));
+ when(response.getOutputStream()).thenReturn(responseOutput);
+ }
+
+ private void mockConnectorTracker() {
+ when(connectorTracker.getSeckey(streamVariable)).thenReturn(expectedSecurityKey);
+ when(connectorTracker.getStreamVariable(connectorId, variableName)).thenReturn(streamVariable);
+ when(connectorTracker.getConnector(connectorId)).thenReturn(clientConnector);
+ }
+
+ private void mockRequest() throws IOException {
+ when(request.getPathInfo()).thenReturn("/" + ServletPortletHelper.UPLOAD_URL_PREFIX + uiId + "/"+ connectorId + "/" + variableName + "/" + expectedSecurityKey);
+ when(request.getInputStream()).thenReturn(createInputStream("foobar"));
+ when(request.getHeader("Content-Length")).thenReturn("6");
+ when(request.getContentType()).thenReturn("foobar");
+ }
+
+ private InputStream createInputStream(final String content) {
+ return new InputStream() {
+ int counter = 0;
+ byte[] msg = content.getBytes();
@Override
public int read() throws IOException {
- counter++;
- if (counter > 6) {
- throw new RuntimeException(
- "-1 is ignored by FileUploadHandler");
+ if(counter > msg.length + 1) {
+ throw new AssertionError("-1 was ignored by FileUploadHandler.");
+ }
+
+ if(counter >= msg.length) {
+ counter++;
+ return -1;
}
- return -1;
- }
+ return msg[counter++];
+ }
};
- request = Mockito.mock(VaadinRequest.class);
- Mockito.when(request.getInputStream()).thenReturn(inputStream);
- Mockito.when(request.getHeader("Content-Length")).thenReturn("211");
}
+ private void mockUi() {
+ when(ui.getConnectorTracker()).thenReturn(connectorTracker);
+ when(session.getUIById(uiId)).thenReturn(ui);
+ }
+
+ /**
+ * Tests whether we get infinite loop if InputStream is already read (#10096)
+ */
@Test(expected = IOException.class)
- public void testStreamEnded() throws IOException {
+ public void exceptionIsThrownOnUnexpectedEnd() throws IOException {
+ when(request.getInputStream()).thenReturn(createInputStream(""));
+ when(request.getHeader("Content-Length")).thenReturn("1");
+
handler.doHandleSimpleMultipartFileUpload(null, request, null, null,
null, null, null);
+ }
+
+ @Test
+ public void responseIsSentOnCorrectSecurityKey() throws IOException {
+ when(connectorTracker.getSeckey(streamVariable)).thenReturn(expectedSecurityKey);
+
+ handler.handleRequest(session, request, response);
+ verify(responseOutput).close();
}
+ @Test
+ public void responseIsNotSentOnIncorrectSecurityKey() throws IOException {
+ when(connectorTracker.getSeckey(streamVariable)).thenReturn("another key expected");
+
+ handler.handleRequest(session, request, response);
+
+ verifyZeroInteractions(responseOutput);
+ }
+
+ @Test
+ public void responseIsNotSentOnMissingSecurityKey() throws IOException {
+ when(connectorTracker.getSeckey(streamVariable)).thenReturn(null);
+
+ handler.handleRequest(session, request, response);
+
+ verifyZeroInteractions(responseOutput);
+ }
}
diff --git a/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java b/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java
index f734d76633..6e81af97a3 100644
--- a/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java
+++ b/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java
@@ -4,9 +4,25 @@ import junit.framework.TestCase;
import com.vaadin.data.util.converter.StringToBooleanConverter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
public class StringToBooleanConverterTest extends TestCase {
StringToBooleanConverter converter = new StringToBooleanConverter();
+ StringToBooleanConverter yesNoConverter = new StringToBooleanConverter("yes","no");
+ StringToBooleanConverter localeConverter = new StringToBooleanConverter() {
+ @Override
+ public String getFalseString(Locale locale) {
+ return SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,locale).format(new Date(3000000000000L));
+ }
+
+ @Override
+ public String getTrueString(Locale locale) {
+ return SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,locale).format(new Date(2000000000000L));
+ }
+ };
public void testNullConversion() {
assertEquals(null, converter.convertToModel(null, Boolean.class, null));
@@ -20,4 +36,22 @@ public class StringToBooleanConverterTest extends TestCase {
assertTrue(converter.convertToModel("true", Boolean.class, null));
assertFalse(converter.convertToModel("false", Boolean.class, null));
}
+
+ public void testYesNoValueConversion() {
+ assertTrue(yesNoConverter.convertToModel("yes", Boolean.class, null));
+ assertFalse(yesNoConverter.convertToModel("no", Boolean.class, null));
+
+ assertEquals("yes", yesNoConverter.convertToPresentation(true, String.class, null));
+ assertEquals("no", yesNoConverter.convertToPresentation(false, String.class, null));
+ }
+
+
+ public void testLocale() {
+ assertEquals("May 18, 2033", localeConverter.convertToPresentation(true, String.class, Locale.US));
+ assertEquals("January 24, 2065", localeConverter.convertToPresentation(false, String.class, Locale.US));
+
+ assertEquals("18. Mai 2033", localeConverter.convertToPresentation(true, String.class, Locale.GERMANY));
+ assertEquals("24. Januar 2065", localeConverter.convertToPresentation(false, String.class, Locale.GERMANY));
+ }
+
}
diff --git a/server/tests/src/com/vaadin/tests/data/converter/StringToEnumConverterTest.java b/server/tests/src/com/vaadin/tests/data/converter/StringToEnumConverterTest.java
index a4c3732e1f..59c1ed133a 100644
--- a/server/tests/src/com/vaadin/tests/data/converter/StringToEnumConverterTest.java
+++ b/server/tests/src/com/vaadin/tests/data/converter/StringToEnumConverterTest.java
@@ -1,13 +1,14 @@
package com.vaadin.tests.data.converter;
-import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.Converter.ConversionException;
import com.vaadin.data.util.converter.ReverseConverter;
import com.vaadin.data.util.converter.StringToEnumConverter;
-public class StringToEnumConverterTest extends TestCase {
+public class StringToEnumConverterTest {
public static enum FooEnum {
VALUE1, SOME_VALUE, FOO_BAR_BAZ, Bar, nonStandardCase, _HUGH;
@@ -17,56 +18,64 @@ public class StringToEnumConverterTest extends TestCase {
Converter<Enum, String> reverseConverter = new ReverseConverter<Enum, String>(
converter);
+ @Test
public void testEmptyStringConversion() {
- assertEquals(null, converter.convertToModel("", Enum.class, null));
+ Assert.assertEquals(null,
+ converter.convertToModel("", Enum.class, null));
}
+ @Test
public void testInvalidEnumClassConversion() {
try {
converter.convertToModel("Foo", Enum.class, null);
- fail("No exception thrown");
+ Assert.fail("No exception thrown");
} catch (ConversionException e) {
// OK
}
}
+ @Test
public void testNullConversion() {
- assertEquals(null, converter.convertToModel(null, Enum.class, null));
+ Assert.assertEquals(null,
+ converter.convertToModel(null, Enum.class, null));
}
+ @Test
public void testReverseNullConversion() {
- assertEquals(null,
+ Assert.assertEquals(null,
reverseConverter.convertToModel(null, String.class, null));
}
+ @Test
public void testValueConversion() {
- assertEquals(FooEnum.VALUE1,
+ Assert.assertEquals(FooEnum.VALUE1,
converter.convertToModel("Value1", FooEnum.class, null));
- assertEquals(FooEnum.SOME_VALUE,
+ Assert.assertEquals(FooEnum.SOME_VALUE,
converter.convertToModel("Some value", FooEnum.class, null));
- assertEquals(FooEnum.FOO_BAR_BAZ,
+ Assert.assertEquals(FooEnum.FOO_BAR_BAZ,
converter.convertToModel("Foo bar baz", FooEnum.class, null));
- assertEquals(FooEnum.Bar,
+ Assert.assertEquals(FooEnum.Bar,
converter.convertToModel("Bar", FooEnum.class, null));
- assertEquals(FooEnum.nonStandardCase, converter.convertToModel(
+ Assert.assertEquals(FooEnum.nonStandardCase, converter.convertToModel(
"Nonstandardcase", FooEnum.class, null));
- assertEquals(FooEnum._HUGH,
+ Assert.assertEquals(FooEnum._HUGH,
converter.convertToModel("_hugh", FooEnum.class, null));
}
+ @Test
public void testReverseValueConversion() {
- assertEquals("Value1", reverseConverter.convertToModel(FooEnum.VALUE1,
- String.class, null));
- assertEquals("Some value", reverseConverter.convertToModel(
+ Assert.assertEquals("Value1", reverseConverter.convertToModel(
+ FooEnum.VALUE1, String.class, null));
+ Assert.assertEquals("Some value", reverseConverter.convertToModel(
FooEnum.SOME_VALUE, String.class, null));
- assertEquals("Foo bar baz", reverseConverter.convertToModel(
+ Assert.assertEquals("Foo bar baz", reverseConverter.convertToModel(
FooEnum.FOO_BAR_BAZ, String.class, null));
- assertEquals("Bar", reverseConverter.convertToModel(FooEnum.Bar,
+ Assert.assertEquals("Bar", reverseConverter.convertToModel(FooEnum.Bar,
String.class, null));
- assertEquals("Nonstandardcase", reverseConverter.convertToModel(
+ Assert.assertEquals("Nonstandardcase", reverseConverter.convertToModel(
FooEnum.nonStandardCase, String.class, null));
- assertEquals("_hugh", reverseConverter.convertToModel(FooEnum._HUGH,
- String.class, null));
+ Assert.assertEquals("_hugh", reverseConverter.convertToModel(
+ FooEnum._HUGH, String.class, null));
}
diff --git a/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java b/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java
index acee3e2ca8..6510d8ad40 100644
--- a/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java
+++ b/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java
@@ -203,7 +203,7 @@ public class DesignFormatterTest {
ShortcutAction action = new ShortcutAction("&^d");
String formatted = formatter.format(action);
// note the space here - it separates key combination from caption
- assertEquals("alt-ctrl-d d", formatted);
+ assertEquals("ctrl-alt-d d", formatted);
ShortcutAction result = formatter
.parse(formatted, ShortcutAction.class);
@@ -215,7 +215,7 @@ public class DesignFormatterTest {
ShortcutAction action = new ShortcutAction(null, KeyCode.D, new int[] {
ModifierKey.ALT, ModifierKey.CTRL });
String formatted = formatter.format(action);
- assertEquals("alt-ctrl-d", formatted);
+ assertEquals("ctrl-alt-d", formatted);
ShortcutAction result = formatter
.parse(formatted, ShortcutAction.class);
diff --git a/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java b/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java
index 9603032ce5..829ad0455d 100644
--- a/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java
+++ b/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java
@@ -73,7 +73,7 @@ public class ClassesSerializableTest extends TestCase {
"com\\.vaadin\\.server\\.AbstractClientConnector\\$1\\$1", //
"com\\.vaadin\\.server\\.JsonCodec\\$1", //
"com\\.vaadin\\.server\\.communication\\.PushConnection", //
- "com\\.vaadin\\.server\\.communication\\.AtmospherePushConnection", //
+ "com\\.vaadin\\.server\\.communication\\.AtmospherePushConnection.*", //
"com\\.vaadin\\.util\\.ConnectorHelper", //
"com\\.vaadin\\.server\\.VaadinSession\\$FutureAccess", //
"com\\.vaadin\\.external\\..*", //
diff --git a/server/tests/src/com/vaadin/tests/server/component/button/ButtonDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/button/ButtonDeclarativeTest.java
index 51abf6be96..b1c10789b4 100644
--- a/server/tests/src/com/vaadin/tests/server/component/button/ButtonDeclarativeTest.java
+++ b/server/tests/src/com/vaadin/tests/server/component/button/ButtonDeclarativeTest.java
@@ -98,7 +98,7 @@ public class ButtonDeclarativeTest extends DeclarativeTestBase<Button> {
@Test
public void testAttributes() {
String design = "<v-button tabindex=3 plain-text='' icon-alt=OK "
- + "click-shortcut=ctrl-shift-o></v-button>";
+ + "click-shortcut=shift-ctrl-o></v-button>";
Button b = new Button("");
b.setTabIndex(3);
b.setIconAlternateText("OK");
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java b/server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java
deleted file mode 100644
index 9ecf131c5b..0000000000
--- a/server/tests/src/com/vaadin/tests/server/component/grid/DataProviderExtension.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.grid;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.vaadin.data.Container;
-import com.vaadin.data.Container.Indexed;
-import com.vaadin.data.Item;
-import com.vaadin.data.Property;
-import com.vaadin.data.RpcDataProviderExtension;
-import com.vaadin.data.RpcDataProviderExtension.DataProviderKeyMapper;
-import com.vaadin.data.util.IndexedContainer;
-
-public class DataProviderExtension {
- private RpcDataProviderExtension dataProvider;
- private DataProviderKeyMapper keyMapper;
- private Container.Indexed container;
-
- private static final Object ITEM_ID1 = "itemid1";
- private static final Object ITEM_ID2 = "itemid2";
- private static final Object ITEM_ID3 = "itemid3";
-
- private static final Object PROPERTY_ID1_STRING = "property1";
-
- @Before
- public void setup() {
- container = new IndexedContainer();
- populate(container);
-
- dataProvider = new RpcDataProviderExtension(container);
- keyMapper = dataProvider.getKeyMapper();
- }
-
- private static void populate(Indexed container) {
- container.addContainerProperty(PROPERTY_ID1_STRING, String.class, "");
- for (Object itemId : Arrays.asList(ITEM_ID1, ITEM_ID2, ITEM_ID3)) {
- final Item item = container.addItem(itemId);
- @SuppressWarnings("unchecked")
- final Property<String> stringProperty = item
- .getItemProperty(PROPERTY_ID1_STRING);
- stringProperty.setValue(itemId.toString());
- }
- }
-
- @Test
- public void pinBasics() {
- assertFalse("itemId1 should not start as pinned",
- keyMapper.isPinned(ITEM_ID2));
-
- keyMapper.pin(ITEM_ID1);
- assertTrue("itemId1 should now be pinned", keyMapper.isPinned(ITEM_ID1));
-
- keyMapper.unpin(ITEM_ID1);
- assertFalse("itemId1 should not be pinned anymore",
- keyMapper.isPinned(ITEM_ID2));
- }
-
- @Test(expected = IllegalStateException.class)
- public void doublePinning() {
- keyMapper.pin(ITEM_ID1);
- keyMapper.pin(ITEM_ID1);
- }
-
- @Test(expected = IllegalStateException.class)
- public void nonexistentUnpin() {
- keyMapper.unpin(ITEM_ID1);
- }
-}
diff --git a/server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java
index 1d233af494..607fb471b9 100644
--- a/server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java
+++ b/server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java
@@ -71,8 +71,9 @@ public class WindowDeclarativeTest extends DeclarativeTestBase<Window> {
expected.setClosable(!expected.isClosable());
expected.setDraggable(!expected.isDraggable());
- expected.setCloseShortcut(KeyCode.ESCAPE, ModifierKey.CTRL,
- ModifierKey.ALT);
+ expected.removeAllCloseShortcuts();
+ expected.addCloseShortcut(KeyCode.ESCAPE, ModifierKey.ALT,
+ ModifierKey.CTRL);
expected.setAssistivePrefix("Hello");
expected.setAssistivePostfix("World");
@@ -86,6 +87,40 @@ public class WindowDeclarativeTest extends DeclarativeTestBase<Window> {
}
@Test
+ public void testMultiCloseShortcuts() {
+
+ Window expected = new Window();
+
+ // Add two shortcuts - should now contain three (default escape + two
+ // added)
+ expected.addCloseShortcut(KeyCode.SPACEBAR);
+ expected.addCloseShortcut(KeyCode.ARROW_LEFT, ModifierKey.ALT,
+ ModifierKey.CTRL);
+
+ // Try to add the same shortcut again, should be no-op
+ expected.addCloseShortcut(KeyCode.ARROW_LEFT, ModifierKey.CTRL,
+ ModifierKey.ALT);
+
+ // Add a third shortcut, should total four (default escape + three
+ // added)
+ expected.addCloseShortcut(KeyCode.ARROW_RIGHT, ModifierKey.CTRL);
+
+ // Test validity
+ String design = "<v-window close-shortcut='escape spacebar ctrl-alt-left ctrl-right' />";
+ testRead(design, expected);
+ testWrite(design, expected);
+
+ // Try removing the spacebar shortcut
+ expected.removeCloseShortcut(KeyCode.SPACEBAR);
+
+ // Test again
+ design = "<v-window close-shortcut='escape ctrl-alt-left ctrl-right' />";
+ testRead(design, expected);
+ testWrite(design, expected);
+
+ }
+
+ @Test
public void testInvalidPosition() {
assertInvalidPosition("");
assertInvalidPosition("1");
diff --git a/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java b/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java
index eb07fae07f..cea8df0ba6 100644
--- a/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java
+++ b/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java
@@ -15,8 +15,17 @@
*/
package com.vaadin.tests.server.renderer;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.Date;
+import java.util.Locale;
+
+import org.junit.Before;
+import org.junit.Test;
+
import com.vaadin.data.Item;
-import com.vaadin.data.RpcDataProviderExtension;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.StringToIntegerConverter;
@@ -24,22 +33,15 @@ import com.vaadin.server.VaadinSession;
import com.vaadin.tests.server.component.grid.TestGrid;
import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.AbstractRenderer;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.renderers.ButtonRenderer;
import com.vaadin.ui.renderers.DateRenderer;
import com.vaadin.ui.renderers.HtmlRenderer;
import com.vaadin.ui.renderers.NumberRenderer;
import com.vaadin.ui.renderers.TextRenderer;
-import elemental.json.JsonValue;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Date;
-import java.util.Locale;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import elemental.json.JsonValue;
public class RendererTest {
@@ -259,7 +261,7 @@ public class RendererTest {
}
private JsonValue render(Column column, Object value) {
- return RpcDataProviderExtension.encodeValue(value,
- column.getRenderer(), column.getConverter(), grid.getLocale());
+ return AbstractRenderer.encodeValue(value, column.getRenderer(),
+ column.getConverter(), grid.getLocale());
}
}
diff --git a/shared/src/com/vaadin/shared/VBrowserDetails.java b/shared/src/com/vaadin/shared/VBrowserDetails.java
index 561b6c76d0..d0de8ffb9f 100644
--- a/shared/src/com/vaadin/shared/VBrowserDetails.java
+++ b/shared/src/com/vaadin/shared/VBrowserDetails.java
@@ -41,6 +41,7 @@ public class VBrowserDetails implements Serializable {
private boolean isFirefox = false;
private boolean isOpera = false;
private boolean isIE = false;
+ private boolean isEdge = false;
private boolean isPhantomJS = false;
private boolean isWindowsPhone;
@@ -88,6 +89,16 @@ public class VBrowserDetails implements Serializable {
isSafari = !isChrome && !isIE && userAgent.indexOf("safari") != -1;
isFirefox = userAgent.indexOf(" firefox/") != -1;
isPhantomJS = userAgent.indexOf("phantomjs/") != -1;
+ if (userAgent.indexOf(" edge/") != -1) {
+ isEdge = true;
+ isChrome = false;
+ isOpera = false;
+ isIE = false;
+ isSafari = false;
+ isFirefox = false;
+ isWebKit = false;
+ isGecko = false;
+ }
// chromeframe
isChromeFrameCapable = userAgent.indexOf("chromeframe") != -1;
@@ -115,6 +126,8 @@ public class VBrowserDetails implements Serializable {
tmp = tmp.replaceFirst("([0-9]+\\.[0-9]+).*", "$1");
browserEngineVersion = Float.parseFloat(tmp);
}
+ } else if (isEdge) {
+ browserEngineVersion = 0;
}
} catch (Exception e) {
// Browser engine version parsing failed
@@ -158,6 +171,9 @@ public class VBrowserDetails implements Serializable {
i = userAgent.indexOf("opera/") + 6;
}
parseVersionString(safeSubstring(userAgent, i, i + 5));
+ } else if (isEdge) {
+ int i = userAgent.indexOf(" edge/") + 6;
+ parseVersionString(safeSubstring(userAgent, i, i + 8));
}
} catch (Exception e) {
// Browser version parsing failed
@@ -373,6 +389,15 @@ public class VBrowserDetails implements Serializable {
}
/**
+ * Tests if the browser is Edge.
+ *
+ * @return true if it is Edge, false otherwise
+ */
+ public boolean isEdge() {
+ return isEdge;
+ }
+
+ /**
* Tests if the browser is PhantomJS.
*
* @return true if it is PhantomJS, false otherwise
diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java
index 4bfdb8b6c5..05965ea56c 100644
--- a/shared/src/com/vaadin/shared/data/DataProviderRpc.java
+++ b/shared/src/com/vaadin/shared/data/DataProviderRpc.java
@@ -91,4 +91,16 @@ public interface DataProviderRpc extends ClientRpc {
* the size of the new data set
*/
public void resetDataAndSize(int size);
+
+ /**
+ * Informs the client that rows have been updated. The client-side
+ * DataSource will map the given data to correct index if it should be in
+ * the cache.
+ *
+ * @since 7.6
+ * @param rowArray
+ * array of updated rows
+ */
+ @NoLayout
+ public void updateRowData(JsonArray rowArray);
}
diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java
index 0d9b919a4e..4b553dda68 100644
--- a/shared/src/com/vaadin/shared/data/DataRequestRpc.java
+++ b/shared/src/com/vaadin/shared/data/DataRequestRpc.java
@@ -16,10 +16,12 @@
package com.vaadin.shared.data;
-import com.vaadin.shared.annotations.NoLoadingIndicator;
import com.vaadin.shared.annotations.Delayed;
+import com.vaadin.shared.annotations.NoLoadingIndicator;
import com.vaadin.shared.communication.ServerRpc;
+import elemental.json.JsonArray;
+
/**
* RPC interface used for requesting container data to the client.
*
@@ -45,15 +47,13 @@ public interface DataRequestRpc extends ServerRpc {
int firstCachedRowIndex, int cacheSize);
/**
- * Informs the server that an item referenced with a key pinned status has
- * changed. This is a delayed call that happens along with next rpc call to
- * server.
+ * Informs the server that items have been dropped from the client cache.
*
- * @param key
- * key mapping to item
- * @param isPinned
- * pinned status of referenced item
+ * @since 7.6
+ * @param rowKeys
+ * array of dropped keys mapping to items
*/
@Delayed
- public void setPinned(String key, boolean isPinned);
+ @NoLoadingIndicator
+ public void dropRows(JsonArray rowKeys);
}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java
index 3c6d993482..ac1b1d5a78 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java
@@ -15,8 +15,6 @@
*/
package com.vaadin.shared.ui.grid;
-import java.util.Set;
-
import com.vaadin.shared.communication.ClientRpc;
/**
@@ -57,19 +55,4 @@ public interface GridClientRpc extends ClientRpc {
* Command client Grid to recalculate column widths.
*/
public void recalculateColumnWidths();
-
- /**
- * Informs the GridConnector on how the indexing of details connectors has
- * changed.
- *
- * @since 7.5.0
- * @param connectorChanges
- * the indexing changes of details connectors
- * @param fetchId
- * the id of the request for fetching the changes. A negative
- * number indicates a push (not requested by the client side)
- */
- public void setDetailsConnectorChanges(
- Set<DetailsConnectorChange> connectorChanges, int fetchId);
-
}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
index 0606e4b1cc..5b2ac96975 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java
@@ -74,4 +74,19 @@ public final class GridConstants implements Serializable {
/** The default cancel button caption in the editor */
public static final String DEFAULT_CANCEL_CAPTION = "Cancel";
+
+ /**
+ * Event ID constant for editor open event
+ */
+ public static final String EDITOR_OPEN_EVENT_ID = "editorOpen";
+
+ /**
+ * Event ID constant for editor move event
+ */
+ public static final String EDITOR_MOVE_EVENT_ID = "editorMove";
+
+ /**
+ * Event ID constant for editor close event
+ */
+ public static final String EDITOR_CLOSE_EVENT_ID = "editorClose";
}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
index dca55c11c4..8d64794b41 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java
@@ -29,14 +29,35 @@ import com.vaadin.shared.data.sort.SortDirection;
*/
public interface GridServerRpc extends ServerRpc {
- void select(List<String> newSelection);
-
- void selectAll();
-
void sort(String[] columnIds, SortDirection[] directions,
boolean userOriginated);
/**
+ * Informs the server that the editor was opened (fresh) on a certain row
+ *
+ * @param rowKey
+ * a key identifying item the editor was opened on
+ */
+ void editorOpen(String rowKey);
+
+ /**
+ * Informs the server that the editor was reopened (without closing it in
+ * between) on another row
+ *
+ * @param rowKey
+ * a key identifying item the editor was opened on
+ */
+ void editorMove(String rowKey);
+
+ /**
+ * Informs the server that the editor was closed
+ *
+ * @param rowKey
+ * a key identifying item the editor was opened on
+ */
+ void editorClose(String rowKey);
+
+ /**
* Informs the server that an item has been clicked in Grid.
*
* @param rowKey
@@ -61,23 +82,6 @@ public interface GridServerRpc extends ServerRpc {
List<String> oldColumnOrder);
/**
- * This is a trigger for Grid to send whatever has changed regarding the
- * details components.
- * <p>
- * The components can't be sent eagerly, since they are generated as a side
- * effect in
- * {@link com.vaadin.data.RpcDataProviderExtension#beforeClientResponse(boolean)}
- * , and that is too late to change the hierarchy. So we need this
- * round-trip to work around that limitation.
- *
- * @since 7.5.0
- * @param fetchId
- * an unique identifier for the request
- * @see com.vaadin.ui.Grid#setDetailsVisible(Object, boolean)
- */
- void sendDetailsComponents(int fetchId);
-
- /**
* Informs the server that the column's visibility has been changed.
*
* @since 7.5.0
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java
index c23c931683..e51b1a78a7 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridState.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java
@@ -19,9 +19,9 @@ package com.vaadin.shared.ui.grid;
import java.util.ArrayList;
import java.util.List;
-import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.annotations.DelegateToWidget;
import com.vaadin.shared.data.sort.SortDirection;
+import com.vaadin.shared.ui.TabIndexState;
/**
* The shared state for the {@link com.vaadin.ui.components.grid.Grid} component
@@ -29,7 +29,7 @@ import com.vaadin.shared.data.sort.SortDirection;
* @since 7.4
* @author Vaadin Ltd
*/
-public class GridState extends AbstractComponentState {
+public class GridState extends TabIndexState {
/**
* A description of which of the three bundled SelectionModels is currently
@@ -103,6 +103,20 @@ public class GridState extends AbstractComponentState {
public static final String JSONKEY_CELLSTYLES = "cs";
/**
+ * The key in which a row's description can be found
+ *
+ * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String)
+ */
+ public static final String JSONKEY_ROWDESCRIPTION = "rd";
+
+ /**
+ * The key in which a cell's description can be found
+ *
+ * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String)
+ */
+ public static final String JSONKEY_CELLDESCRIPTION = "cd";
+
+ /**
* The key that tells whether details are visible for the row.
*
* @since 7.5.0
@@ -115,6 +129,13 @@ public class GridState extends AbstractComponentState {
public static final String JSONKEY_DETAILS_VISIBLE = "dv";
/**
+ * The key that tells whether row is selected.
+ *
+ * @since
+ */
+ public static final String JSONKEY_SELECTED = "s";
+
+ /**
* Columns in grid.
*/
public List<GridColumnState> columns = new ArrayList<GridColumnState>();
@@ -139,14 +160,6 @@ public class GridState extends AbstractComponentState {
@DelegateToWidget
public HeightMode heightMode = HeightMode.CSS;
- // instantiated just to avoid NPEs
- public List<String> selectedKeys = new ArrayList<String>();
-
- public SharedSelectionMode selectionMode;
-
- /** Whether single select mode can be cleared through the UI */
- public boolean singleSelectDeselectAllowed = true;
-
/** Keys of the currently sorted columns */
public String[] sortColumns = new String[0];
@@ -156,10 +169,12 @@ public class GridState extends AbstractComponentState {
/** The enabled state of the editor interface */
public boolean editorEnabled = false;
- /** Whether row data might contain generated row styles */
- public boolean hasRowStyleGenerator;
- /** Whether row data might contain generated cell styles */
- public boolean hasCellStyleGenerator;
+ /** Buffered editor mode */
+ @DelegateToWidget
+ public boolean editorBuffered = true;
+
+ /** Whether rows and/or cells have generated descriptions (tooltips) */
+ public boolean hasDescriptions;
/** The caption for the save button in the editor */
@DelegateToWidget
diff --git a/shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelServerRpc.java
new file mode 100644
index 0000000000..e7324552f4
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelServerRpc.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.shared.ui.grid.selection;
+
+import java.util.List;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * ServerRpc for MultiSelectionModel.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public interface MultiSelectionModelServerRpc extends ServerRpc {
+
+ /**
+ * Select a list of rows based on their row keys on the server-side.
+ *
+ * @param rowKeys
+ * list of row keys to select
+ */
+ public void select(List<String> rowKeys);
+
+ /**
+ * Deselect a list of rows based on their row keys on the server-side.
+ *
+ * @param rowKeys
+ * list of row keys to deselect
+ */
+ public void deselect(List<String> rowKeys);
+
+ /**
+ * Selects all rows on the server-side.
+ */
+ public void selectAll();
+
+ /**
+ * Deselects all rows on the server-side.
+ */
+ public void deselectAll();
+}
diff --git a/shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelState.java b/shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelState.java
new file mode 100644
index 0000000000..3ffd0d0f93
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/grid/selection/MultiSelectionModelState.java
@@ -0,0 +1,31 @@
+/*
+ * 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.shared.ui.grid.selection;
+
+import com.vaadin.shared.communication.SharedState;
+
+/**
+ * SharedState object for MultiSelectionModel.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class MultiSelectionModelState extends SharedState {
+
+ /* Select All -checkbox status */
+ public boolean allSelected;
+
+}
diff --git a/shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelServerRpc.java
new file mode 100644
index 0000000000..3e2a8ec847
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelServerRpc.java
@@ -0,0 +1,35 @@
+/*
+ * 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.shared.ui.grid.selection;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * ServerRpc for SingleSelectionModel.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public interface SingleSelectionModelServerRpc extends ServerRpc {
+
+ /**
+ * Selects a row on server-side.
+ *
+ * @param rowKey
+ * row key of selected row; {@code null} if deselect
+ */
+ public void select(String rowKey);
+}
diff --git a/shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelState.java b/shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelState.java
new file mode 100644
index 0000000000..719b60b2ba
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/grid/selection/SingleSelectionModelState.java
@@ -0,0 +1,30 @@
+/*
+ * 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.shared.ui.grid.selection;
+
+import com.vaadin.shared.communication.SharedState;
+
+/**
+ * SharedState object for SingleSelectionModel.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class SingleSelectionModelState extends SharedState {
+
+ /* Allow deselecting rows */
+ public boolean deselectAllowed;
+}
diff --git a/shared/src/com/vaadin/shared/ui/table/TableConstants.java b/shared/src/com/vaadin/shared/ui/table/TableConstants.java
index fd1c61c772..e782492e9d 100644
--- a/shared/src/com/vaadin/shared/ui/table/TableConstants.java
+++ b/shared/src/com/vaadin/shared/ui/table/TableConstants.java
@@ -23,6 +23,7 @@ public class TableConstants implements Serializable {
public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick";
public static final String COLUMN_RESIZE_EVENT_ID = "columnResize";
public static final String COLUMN_REORDER_EVENT_ID = "columnReorder";
+ public static final String COLUMN_COLLAPSE_EVENT_ID = "columnCollapse";
@Deprecated
public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft";
diff --git a/uitest/integration_tests.xml b/uitest/integration_tests.xml
index 395627a4a7..20d0d2147d 100644
--- a/uitest/integration_tests.xml
+++ b/uitest/integration_tests.xml
@@ -411,7 +411,8 @@
<antcall target="integration-test-osgi" />
<antcall target="integration-test-tomcat7apacheproxy" />
<antcall target="integration-test-websphere8" />
- <antcall target="integration-test-websphereportal8" />
+ <!-- Currently the test system does not have a server for automatic testing of WebSphere Portal 8 -->
+ <!-- <antcall target="integration-test-websphereportal8" /> -->
</parallel>
</target>
diff --git a/uitest/ivy.xml b/uitest/ivy.xml
index cb2d5cff45..e17e094f79 100644
--- a/uitest/ivy.xml
+++ b/uitest/ivy.xml
@@ -31,7 +31,7 @@
rev="4.2.0.Final" conf="build,ide -> default" />
<!-- Google App Engine -->
<dependency org="com.google.appengine" name="appengine-api-1.0-sdk"
- rev="1.2.1" conf="build-provided,ide -> default" />
+ rev="1.7.7" conf="build-provided,ide -> default" />
<!-- LIBRARY DEPENDENCIES (compile time) -->
<!-- Project modules -->
diff --git a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java
index c6ccd1bf4c..ed0f1a9b4f 100644
--- a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java
+++ b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java
@@ -40,7 +40,7 @@ public class VerifyBrowserVersionTest extends MultiBrowserTest {
// Chrome version does not necessarily match the desired version
// because of auto updates...
browserIdentifier = getExpectedUserAgentString(getDesiredCapabilities())
- + "43";
+ + "44";
} else {
browserIdentifier = getExpectedUserAgentString(desiredCapabilities)
+ desiredCapabilities.getVersion();
diff --git a/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java b/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java
index ddef40b2d0..c8fc96f596 100644
--- a/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java
+++ b/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java
@@ -35,9 +35,13 @@ public class VaadinSessionAttribute extends AbstractTestUI {
new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
- Notification.show(getSession().getAttribute(ATTR_NAME)
- + " & "
- + getSession().getAttribute(Integer.class));
+ Notification notification = new Notification(
+ getSession().getAttribute(ATTR_NAME)
+ + " & "
+ + getSession().getAttribute(
+ Integer.class));
+ notification.setDelayMsec(Notification.DELAY_FOREVER);
+ notification.show(getPage());
}
}));
}
diff --git a/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java b/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java
index b289279b86..aca617aa5a 100644
--- a/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java
+++ b/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java
@@ -20,6 +20,7 @@ import com.vaadin.server.ThemeResource;
import com.vaadin.tests.util.Log;
import com.vaadin.tests.util.LoremIpsum;
import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.themes.BaseTheme;
@@ -242,16 +243,18 @@ public abstract class AbstractComponentTest<T extends AbstractComponent>
createStyleNameSelect(CATEGORY_DECORATIONS);
+ createFocusActions();
}
protected Command<T, Boolean> focusListenerCommand = new Command<T, Boolean>() {
@Override
public void execute(T c, Boolean value, Object data) {
+ FocusNotifier fn = (FocusNotifier) c;
if (value) {
- ((FocusNotifier) c).addListener(AbstractComponentTest.this);
+ fn.addFocusListener(AbstractComponentTest.this);
} else {
- ((FocusNotifier) c).removeListener(AbstractComponentTest.this);
+ fn.removeFocusListener(AbstractComponentTest.this);
}
}
};
@@ -259,10 +262,11 @@ public abstract class AbstractComponentTest<T extends AbstractComponent>
@Override
public void execute(T c, Boolean value, Object data) {
+ BlurNotifier bn = (BlurNotifier) c;
if (value) {
- ((BlurNotifier) c).addListener(AbstractComponentTest.this);
+ bn.addBlurListener(AbstractComponentTest.this);
} else {
- ((BlurNotifier) c).removeListener(AbstractComponentTest.this);
+ bn.removeBlurListener(AbstractComponentTest.this);
}
}
};
@@ -279,6 +283,35 @@ public abstract class AbstractComponentTest<T extends AbstractComponent>
}
+ private void createFocusActions() {
+ if (FocusNotifier.class.isAssignableFrom(getTestClass())) {
+ createFocusListener(CATEGORY_LISTENERS);
+ }
+ if (BlurNotifier.class.isAssignableFrom(getTestClass())) {
+ createBlurListener(CATEGORY_LISTENERS);
+ }
+ if (Focusable.class.isAssignableFrom(getTestClass())) {
+ LinkedHashMap<String, Integer> tabIndexes = new LinkedHashMap<String, Integer>();
+ tabIndexes.put("0", 0);
+ tabIndexes.put("-1", -1);
+ tabIndexes.put("10", 10);
+ createSelectAction("Tab index", "State", tabIndexes, "0",
+ new Command<T, Integer>() {
+ @Override
+ public void execute(T c, Integer tabIndex, Object data) {
+ ((Focusable) c).setTabIndex(tabIndex);
+ }
+ });
+
+ createClickAction("Set focus", "State", new Command<T, Void>() {
+ @Override
+ public void execute(T c, Void value, Object data) {
+ ((Focusable) c).focus();
+ }
+ }, null);
+ }
+ }
+
private void createStyleNameSelect(String category) {
LinkedHashMap<String, String> options = new LinkedHashMap<String, String>();
options.put("-", null);
diff --git a/uitest/src/com/vaadin/tests/components/OutOfSync.java b/uitest/src/com/vaadin/tests/components/OutOfSync.java
new file mode 100644
index 0000000000..8cefffc9d1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/OutOfSync.java
@@ -0,0 +1,55 @@
+package com.vaadin.tests.components;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Notification;
+
+public class OutOfSync extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Button b = new Button("Click me after 1s to be out of sync");
+ b.addClickListener(new ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Notification.show("This code will never be reached");
+ }
+ });
+ setContent(b);
+ Thread t = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ // Remove button but prevent repaint -> causes out of sync
+ // issues
+ getSession().lock();
+ try {
+ setContent(null);
+ getConnectorTracker().markClean(OutOfSync.this);
+ } finally {
+ getSession().unlock();
+ }
+ }
+ });
+ t.start();
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Click the button after 1s when it has been removed server side (causing synchronization problems)";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 10780;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java b/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java
index 0efb519e8d..c6bab3c9b9 100644
--- a/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java
+++ b/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java
@@ -1,55 +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;
-import com.vaadin.server.VaadinRequest;
-import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.ui.Button.ClickListener;
-import com.vaadin.ui.Notification;
-
-public class OutOfSyncTest extends AbstractTestUI {
-
- @Override
- protected void setup(VaadinRequest request) {
- Button b = new Button("Click me after 1s to be out of sync");
- b.addClickListener(new ClickListener() {
-
- @Override
- public void buttonClick(ClickEvent event) {
- Notification.show("This code will never be reached");
- }
- });
- setContent(b);
- Thread t = new Thread(new Runnable() {
-
- @Override
- public void run() {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // Remove button but prevent repaint -> causes out of sync
- // issues
- getSession().lock();
- try {
- setContent(null);
- getConnectorTracker().markClean(OutOfSyncTest.this);
- } finally {
- getSession().unlock();
- }
- }
- });
- t.start();
- }
+import org.junit.Assert;
+import org.junit.Test;
- @Override
- protected String getTestDescription() {
- return "Click the button after 1s when it has been removed server side (causing synchronization problems)";
- }
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class OutOfSyncTest extends MultiBrowserTest {
+
+ @Test
+ public void testClientResync() throws InterruptedException {
+ openTestURL();
+
+ // Wait for server to get rid of the Button
+ sleep(1000);
+
+ // On the first round-trip after the component has been removed, the
+ // server assumes the client will remove the button. How ever (to force
+ // it to be out of sync) the test UI calls markClean() on the Button to
+ // make it not update with the response.
+ $(ButtonElement.class).first().click();
+ Assert.assertTrue(
+ "Button should not have disappeared on the first click.",
+ $(ButtonElement.class).exists());
- @Override
- protected Integer getTicketNumber() {
- return 10780;
+ // Truly out of sync, full resync is forced.
+ $(ButtonElement.class).first().click();
+ Assert.assertFalse("Button should disappear with the second click.",
+ $(ButtonElement.class).exists());
}
}
diff --git a/uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java b/uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java
new file mode 100644
index 0000000000..649ee42986
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.abstractembedded;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import com.vaadin.testbench.parallel.Browser;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class EmbeddedWithNullSourceTest extends MultiBrowserTest {
+
+ @Override
+ public List<DesiredCapabilities> getBrowsersToTest() {
+ // No Flash on PhantomJS, IE 11 has a timeout issue, looks like a
+ // IEDriver problem, not reproduced running locally.
+ return getBrowserCapabilities(Browser.IE8, Browser.IE9, Browser.IE10,
+ Browser.CHROME, Browser.FIREFOX);
+ }
+
+ @Test
+ public void testEmbeddedWithNullSource() throws IOException {
+ openTestURL();
+
+ waitForElementPresent(By.className("v-image"));
+
+ compareScreen("nullSources");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java b/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
index 692ca25b07..496a44a6c1 100644
--- a/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
+++ b/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
@@ -13,8 +13,6 @@ import com.vaadin.data.Property;
import com.vaadin.data.Property.ReadOnlyStatusChangeEvent;
import com.vaadin.data.Property.ReadOnlyStatusChangeListener;
import com.vaadin.data.Property.ValueChangeListener;
-import com.vaadin.event.FieldEvents.BlurNotifier;
-import com.vaadin.event.FieldEvents.FocusNotifier;
import com.vaadin.tests.components.AbstractComponentTest;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.MenuBar;
@@ -29,15 +27,9 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends
@Override
protected void createActions() {
super.createActions();
+
createBooleanAction("Required", CATEGORY_STATE, false, requiredCommand);
createRequiredErrorSelect(CATEGORY_DECORATIONS);
- if (FocusNotifier.class.isAssignableFrom(getTestClass())) {
- createFocusListener(CATEGORY_LISTENERS);
- }
-
- if (BlurNotifier.class.isAssignableFrom(getTestClass())) {
- createBlurListener(CATEGORY_LISTENERS);
- }
createValueChangeListener(CATEGORY_LISTENERS);
createReadOnlyStatusChangeListener(CATEGORY_LISTENERS);
@@ -52,7 +44,6 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends
// * invalidallowed
// * error indicator
//
- // * tabindex
// * validation visible
// * ShortcutListener
diff --git a/uitest/src/com/vaadin/tests/components/button/Buttons2.java b/uitest/src/com/vaadin/tests/components/button/Buttons2.java
index 7526e7dbc3..4f75dfbfef 100644
--- a/uitest/src/com/vaadin/tests/components/button/Buttons2.java
+++ b/uitest/src/com/vaadin/tests/components/button/Buttons2.java
@@ -42,9 +42,6 @@ public class Buttons2<T extends Button> extends AbstractComponentTest<T>
protected void createActions() {
super.createActions();
- createFocusListener(CATEGORY_LISTENERS);
- createBlurListener(CATEGORY_LISTENERS);
-
createBooleanAction("Disable on click", CATEGORY_FEATURES, false,
disableOnClickCommand);
addClickListener(CATEGORY_LISTENERS);
diff --git a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java
index c2dfdb26c1..40dd43abb2 100644
--- a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java
+++ b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java
@@ -5,17 +5,27 @@ import java.text.SimpleDateFormat;
import java.util.Locale;
import com.vaadin.server.VaadinRequest;
-import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Calendar;
import com.vaadin.ui.components.calendar.CalendarComponentEvents;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClick;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClickHandler;
import com.vaadin.ui.components.calendar.event.BasicEvent;
-public class NullEventMoveHandler extends AbstractTestUI {
+public class NullEventMoveHandler extends AbstractTestUIWithLog {
@Override
protected void setup(VaadinRequest request) {
Calendar calendar = getCalendar();
calendar.setHandler((CalendarComponentEvents.EventMoveHandler) null);
+ calendar.setHandler(new EventClickHandler() {
+
+ @Override
+ public void eventClick(EventClick event) {
+ log("Clicked on " + event.getCalendarEvent().getCaption());
+
+ }
+ });
addComponent(calendar);
}
diff --git a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java
index c40cd9ce97..156100310c 100644
--- a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java
+++ b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java
@@ -3,6 +3,7 @@ package com.vaadin.tests.components.calendar;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
+import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
@@ -23,11 +24,25 @@ public class NullEventMoveHandlerTest extends DndActionsTest {
}
@Test
+ public void eventIsClickableWhenNotMovableInMonthView() {
+ getEvent().click();
+ Assert.assertEquals("1. Clicked on foo", getLogRow(0));
+ }
+
+ @Test
public void eventIsNotMovableInWeekView() {
openWeekView();
assertEventCannotBeMoved();
}
+ @Test
+ public void eventIsClickableWhenNotMovableInWeekView() {
+ openWeekView();
+ getEvent().findElement(By.className("v-calendar-event-caption"))
+ .click();
+ Assert.assertEquals("1. Clicked on foo", getLogRow(0));
+ }
+
private void assertEventCannotBeMoved() {
int originalPosition = getEventXPosition();
diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java
new file mode 100644
index 0000000000..2f96724db1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java
@@ -0,0 +1,15 @@
+package com.vaadin.tests.components.combobox;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ComboBox;
+
+public class ComboBoxEmptyItemsKeyboardNavigation extends AbstractTestUI {
+ @Override
+ protected void setup(VaadinRequest request) {
+ ComboBox comboBox = new ComboBox();
+ comboBox.addItems("foo", "bar");
+
+ addComponent(comboBox);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java
new file mode 100644
index 0000000000..c5cbc5eea6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java
@@ -0,0 +1,30 @@
+package com.vaadin.tests.components.combobox;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsEmptyCollection.empty;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import com.vaadin.tests.tb3.newelements.ComboBoxElement;
+
+public class ComboBoxEmptyItemsKeyboardNavigationTest extends MultiBrowserTest {
+
+ @Test
+ public void navigatingUpOnAnEmptyMenuDoesntThrowErrors() {
+ setDebug(true);
+ openTestURL();
+
+ ComboBoxElement combobox = $(ComboBoxElement.class).first();
+ combobox.sendKeys("a", Keys.ARROW_UP);
+
+ List<WebElement> errors = findElements(By.className("SEVERE"));
+
+ assertThat(errors, empty());
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java
new file mode 100644
index 0000000000..407ab7aa04
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java
@@ -0,0 +1,58 @@
+package com.vaadin.tests.components.combobox;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.NativeSelectElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import com.vaadin.tests.tb3.newelements.ComboBoxElement;
+
+public class ComboBoxLargeIconsTest extends MultiBrowserTest {
+ @Override
+ protected Class<?> getUIClass() {
+ return com.vaadin.tests.components.combobox.Comboboxes.class;
+ }
+
+ @Test
+ public void testComboBoxIcons() throws Exception {
+ openTestURL();
+ NativeSelectElement iconSelect = $(NativeSelectElement.class).first();
+ iconSelect.selectByText("16x16");
+
+ ComboBoxElement cb = $(ComboBoxElement.class).caption(
+ "Undefined wide select with 50 items").first();
+ cb.openPopup();
+ compareScreen("icons-16x16-page1");
+ cb.openNextPage();
+ compareScreen("icons-16x16-page2");
+ cb.findElement(By.vaadin("#popup/item0")).click();
+ compareScreen("icons-16x16-selected-1-3-5-9");
+
+ iconSelect.selectByText("32x32");
+ cb.openPopup();
+ compareScreen("icons-32x32-page2");
+
+ // Closes the popup
+ cb.openPopup();
+
+ iconSelect.selectByText("64x64");
+
+ ComboBoxElement pageLength0cb = $(ComboBoxElement.class).caption(
+ "Pagelength 0").first();
+ pageLength0cb.openPopup();
+ pageLength0cb.findElement(By.vaadin("#popup/item1")).click();
+
+ ComboBoxElement cb200px = $(ComboBoxElement.class).caption(
+ "200px wide select with 50 items").first();
+ cb200px.openPopup();
+ cb200px.findElement(By.vaadin("#popup/item1")).click();
+
+ ComboBoxElement cb150px = $(ComboBoxElement.class).caption(
+ "150px wide select with 5 items").first();
+ new Actions(driver).sendKeys(cb150px, Keys.DOWN).perform();
+
+ compareScreen("icons-64x64-page1-highlight-first");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java
new file mode 100644
index 0000000000..9f1c4b9e03
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java
@@ -0,0 +1,40 @@
+package com.vaadin.tests.components.combobox;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.HorizontalLayout;
+
+@Theme("valo")
+public class ComboboxPopupScrolling extends AbstractTestUIWithLog {
+ @Override
+ protected void setup(VaadinRequest request) {
+ ComboBox combobox = new ComboBox("100px wide combobox");
+ combobox.setWidth("100px");
+ combobox.addItem("AMERICAN SAMOA");
+ combobox.addItem("ANTIGUA AND BARBUDA");
+
+ ComboBox combobox2 = new ComboBox("250px wide combobox");
+ combobox2.setWidth("250px");
+ combobox2.addItem("AMERICAN SAMOA");
+ combobox2.addItem("ANTIGUA AND BARBUDA");
+
+ ComboBox combobox3 = new ComboBox("Undefined wide combobox");
+ combobox3.setWidth(null);
+ combobox3.addItem("AMERICAN SAMOA");
+ combobox3.addItem("ANTIGUA AND BARBUDA");
+
+ ComboBox combobox4 = new ComboBox("Another 100px wide combobox");
+ combobox4.setWidth("100px");
+ for (int i = 0; i < 10; i++) {
+ combobox4.addItem("AMERICAN SAMOA " + i);
+ combobox4.addItem("ANTIGUA AND BARBUDA " + i);
+ }
+
+ HorizontalLayout hl = new HorizontalLayout(combobox, combobox2,
+ combobox3, combobox4);
+ addComponent(hl);
+ }
+
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java
new file mode 100644
index 0000000000..ec5bc088da
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.combobox;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class ComboboxPopupScrollingTest extends MultiBrowserTest {
+
+ @Test
+ public void testNoScrollbarsValo() {
+ testNoScrollbars("valo");
+ }
+
+ @Test
+ public void testNoScrollbarsChameleon() {
+ testNoScrollbars("chameleon");
+ }
+
+ @Test
+ public void testNoScrollbarsRuno() {
+ testNoScrollbars("runo");
+ }
+
+ @Test
+ public void testNoScrollbarsReindeer() {
+ testNoScrollbars("reindeer");
+ }
+
+ private void testNoScrollbars(String theme) {
+ openTestURL("theme=" + theme);
+
+ for (CustomComboBoxElement cb : $(CustomComboBoxElement.class).all()) {
+ String caption = cb.getCaption();
+ cb.openPopup();
+ WebElement popup = cb.getSuggestionPopup();
+ WebElement scrollable = popup.findElement(By
+ .className("v-filterselect-suggestmenu"));
+ assertNoHorizontalScrollbar(scrollable, caption);
+ assertNoVerticalScrollbar(scrollable, caption);
+ }
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java b/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java
new file mode 100644
index 0000000000..697d5eb932
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java
@@ -0,0 +1,40 @@
+/*
+ * 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.combobox;
+
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.ComboBoxElement;
+import com.vaadin.testbench.elementsbase.ServerClass;
+
+@ServerClass("com.vaadin.ui.ComboBox")
+public class CustomComboBoxElement extends ComboBoxElement {
+ private static org.openqa.selenium.By bySuggestionPopup = By
+ .vaadin("#popup");
+
+ public WebElement getSuggestionPopup() {
+ ensurePopupOpen();
+ return findElement(bySuggestionPopup);
+ }
+
+ private void ensurePopupOpen() {
+ if (!isElementPresent(bySuggestionPopup)) {
+ openPopup();
+ }
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java
index 7d706ecd30..d5e01a9de8 100644
--- a/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/CustomRendererTest.java
@@ -47,8 +47,8 @@ public class CustomRendererTest extends MultiBrowserTest {
.getText());
grid.getCell(0, 1).click();
- assertEquals("row: 0, key: 0", grid.getCell(0, 1).getText());
- assertEquals("key: 0, itemId: " + CustomRenderer.ITEM_ID,
+ assertEquals("row: 0, key: 1", grid.getCell(0, 1).getText());
+ assertEquals("key: 1, itemId: " + CustomRenderer.ITEM_ID,
findDebugLabel().getText());
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModel.java b/uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModel.java
new file mode 100644
index 0000000000..008c24cdd3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModel.java
@@ -0,0 +1,37 @@
+/*
+ * 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.grid;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.ui.Grid.MultiSelectionModel;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class GridCustomSelectionModel extends AbstractTestUI {
+
+ public static class MySelectionModel extends MultiSelectionModel {
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ PersonTestGrid grid = new PersonTestGrid(500);
+ grid.setSelectionModel(new MySelectionModel());
+ addComponent(grid);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModelTest.java b/uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModelTest.java
new file mode 100644
index 0000000000..976e1e78fe
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridCustomSelectionModelTest.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.grid;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+import com.vaadin.testbench.parallel.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public class GridCustomSelectionModelTest extends MultiBrowserTest {
+
+ @Test
+ public void testCustomSelectionModel() {
+ setDebug(true);
+ openTestURL();
+
+ GridElement grid = $(GridElement.class).first();
+ GridCellElement cell = grid.getCell(0, 0);
+ assertTrue("First column of Grid should not have an input element",
+ cell.findElements(By.className("input")).isEmpty());
+
+ assertFalse("Row should not be selected initially", grid.getRow(0)
+ .isSelected());
+
+ cell.click(5, 5);
+ assertTrue("Click should select row", grid.getRow(0).isSelected());
+ cell.click(5, 5);
+ assertFalse("Click should deselect row", grid.getRow(0).isSelected());
+
+ grid.sendKeys(Keys.SPACE);
+ assertTrue("Space should select row", grid.getRow(0).isSelected());
+ grid.sendKeys(Keys.SPACE);
+ assertFalse("Space should deselect row", grid.getRow(0).isSelected());
+
+ assertNoErrorNotifications();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java
index 1032378a2d..3d7f6da587 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java
@@ -56,7 +56,6 @@ public class GridDetailsDetach extends AbstractTestUI {
layout.addComponent(new Button("Reattach Grid",
new Button.ClickListener() {
-
@Override
public void buttonClick(ClickEvent event) {
gridContainer.removeAllComponents();
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java
index fc79fd1b68..7406daeacd 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java
@@ -70,4 +70,28 @@ public class GridDetailsDetachTest extends MultiBrowserTest {
Assert.assertEquals("Spacer content not visible",
"Extra data for Bean 5", spacers.get(1).getText());
}
+
+ @Test
+ public void testDetachAndImmediateReattach() {
+ setDebug(true);
+ openTestURL();
+
+ $(GridElement.class).first().getCell(3, 0).click();
+ $(GridElement.class).first().getCell(5, 0).click();
+
+ assertNoErrorNotifications();
+
+ // Detach and Re-attach Grid
+ $(ButtonElement.class).get(1).click();
+
+ assertNoErrorNotifications();
+
+ List<WebElement> spacers = findElements(By.className("v-grid-spacer"));
+ Assert.assertEquals("Not enough spacers in DOM", 2, spacers.size());
+ Assert.assertEquals("Spacer content not visible",
+ "Extra data for Bean 3", spacers.get(0).getText());
+ Assert.assertEquals("Spacer content not visible",
+ "Extra data for Bean 5", spacers.get(1).getText());
+ }
+
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java
index 33f66d35be..a395d7e721 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java
@@ -86,9 +86,7 @@ public class GridDetailsLocationTest extends MultiBrowserTest {
for (int rowIndex : params) {
- data.add(new Param(rowIndex, false, false));
data.add(new Param(rowIndex, true, false));
- data.add(new Param(rowIndex, false, true));
data.add(new Param(rowIndex, true, true));
}
@@ -138,23 +136,6 @@ public class GridDetailsLocationTest extends MultiBrowserTest {
}
@Test
- public void testDetailsHeightWithNoGenerator() {
- openTestURL();
- toggleAndScroll(5);
-
- verifyDetailsRowHeight(5, detailsDefaultHeight, 0);
- verifyDetailsDecoratorLocation(5, 0, 0);
-
- toggleAndScroll(0);
-
- verifyDetailsRowHeight(0, detailsDefaultHeight, 0);
- verifyDetailsDecoratorLocation(0, 0, 1);
-
- verifyDetailsRowHeight(5, detailsDefaultHeight, 1);
- verifyDetailsDecoratorLocation(5, 1, 0);
- }
-
- @Test
public void testDetailsHeightWithGenerator() {
openTestURL();
useGenerator(true);
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.java
new file mode 100644
index 0000000000..d2414a8c40
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.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.grid;
+
+import com.vaadin.tests.util.PersonContainer;
+import com.vaadin.ui.Grid;
+
+public class GridEditorFrozenColumnsUI extends GridEditorUI {
+
+ @Override
+ protected Grid createGrid(PersonContainer container) {
+ Grid grid = super.createGrid(container);
+
+ grid.setFrozenColumnCount(2);
+
+ grid.setWidth("600px");
+
+ return grid;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 16727;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Frozen columns should also freeze cells in editor.";
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java
new file mode 100644
index 0000000000..75d71a3c40
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.grid;
+
+import java.io.IOException;
+
+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.interactions.Actions;
+
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+import com.vaadin.testbench.parallel.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public class GridEditorFrozenColumnsUITest extends MultiBrowserTest {
+
+ @Test
+ public void testEditorWithFrozenColumns() throws IOException {
+ openTestURL();
+
+ openEditor(10);
+
+ compareScreen("noscroll");
+
+ scrollGridHorizontallyTo(100);
+
+ compareScreen("scrolled");
+ }
+
+ private void openEditor(int rowIndex) {
+ GridElement grid = $(GridElement.class).first();
+
+ GridCellElement cell = grid.getCell(rowIndex, 1);
+
+ new Actions(driver).moveToElement(cell).doubleClick().build().perform();
+ }
+
+ private void scrollGridHorizontallyTo(double px) {
+ executeScript("arguments[0].scrollLeft = " + px,
+ getGridHorizontalScrollbar());
+ }
+
+ private Object executeScript(String script, WebElement element) {
+ final WebDriver driver = getDriver();
+ if (driver instanceof JavascriptExecutor) {
+ final JavascriptExecutor je = (JavascriptExecutor) driver;
+ return je.executeScript(script, element);
+ } else {
+ throw new IllegalStateException("current driver "
+ + getDriver().getClass().getName() + " is not a "
+ + JavascriptExecutor.class.getSimpleName());
+ }
+ }
+
+ private WebElement getGridHorizontalScrollbar() {
+ return getDriver()
+ .findElement(
+ By.xpath("//div[contains(@class, \"v-grid-scroller-horizontal\")]"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java
index 60e241bae3..0a302967e8 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java
@@ -28,6 +28,10 @@ public class GridEditorUI extends AbstractTestUI {
protected void setup(VaadinRequest request) {
PersonContainer container = PersonContainer.createWithTestData();
+ addComponent(createGrid(container));
+ }
+
+ protected Grid createGrid(PersonContainer container) {
Grid grid = new Grid(container);
// Don't use address since there's no converter
@@ -43,7 +47,7 @@ public class GridEditorUI extends AbstractTestUI {
grid.getColumn("phoneNumber").getEditorField().setReadOnly(true);
- addComponent(grid);
+ return grid;
}
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java
index 47dc90e33a..3d0b3bb071 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java
@@ -45,7 +45,7 @@ public class GridEditorUITest extends MultiBrowserTest {
openEditor(10);
- assertTrue("Edtor should be opened with a password field",
+ assertTrue("Editor should be opened with a password field",
isElementPresent(PasswordFieldElement.class));
assertFalse("Notification was present",
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java b/uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java
new file mode 100644
index 0000000000..31fe0275a5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java
@@ -0,0 +1,148 @@
+package com.vaadin.tests.components.grid;
+
+import java.util.Calendar;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+
+import com.vaadin.annotations.Push;
+import com.vaadin.annotations.Theme;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.event.SelectionEvent;
+import com.vaadin.event.SelectionEvent.SelectionListener;
+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.Grid;
+import com.vaadin.ui.Grid.SelectionMode;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+@Push
+@Theme("valo")
+@SuppressWarnings("serial")
+public class GridFastAsyncUpdate extends AbstractTestUI {
+
+ private final Runnable addRowsTask = new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("Logging...");
+ try {
+ Random random = new Random();
+ while (!Thread.currentThread().isInterrupted()) {
+ Thread.sleep(random.nextInt(100));
+
+ GridFastAsyncUpdate.this.access(new Runnable() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void run() {
+
+ ++counter;
+ Item item = container.addItem(counter);
+ item.getItemProperty("sequenceNumber").setValue(
+ String.valueOf(counter));
+ item.getItemProperty("millis").setValue(
+ String.valueOf(Calendar.getInstance()
+ .getTimeInMillis() - loggingStart));
+ item.getItemProperty("level").setValue(
+ Level.INFO.toString());
+ item.getItemProperty("message").setValue("Message");
+ if (grid != null && !scrollLock) {
+ grid.scrollToEnd();
+ }
+ }
+ });
+ }
+ } catch (InterruptedException e) {
+ System.out.println("logging thread interrupted");
+ }
+ }
+ };
+
+ private int counter;
+
+ private Grid grid;
+ private IndexedContainer container;
+ private long loggingStart;
+ private volatile boolean scrollLock = false;
+
+ @Override
+ protected void setup(VaadinRequest vaadinRequest) {
+ final VerticalLayout layout = new VerticalLayout();
+ layout.setSizeFull();
+ layout.setMargin(true);
+ addComponent(layout);
+
+ HorizontalLayout buttons = new HorizontalLayout();
+ layout.addComponent(buttons);
+
+ final ExecutorService logExecutor = Executors.newSingleThreadExecutor();
+
+ final Button logButton = new Button("Start logging");
+ logButton.addClickListener(new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ if ("Start logging".equals(logButton.getCaption())) {
+ loggingStart = Calendar.getInstance().getTimeInMillis();
+ logExecutor.submit(addRowsTask);
+ logButton.setCaption("Stop logging");
+ } else {
+ System.out.println("Stop logging...");
+ try {
+ logExecutor.shutdownNow();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ logButton.setCaption("Start logging");
+ }
+ }
+ });
+ buttons.addComponent(logButton);
+
+ final Button scrollButton = new Button("Stop scrolling");
+ scrollButton.addClickListener(new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ if (!scrollLock) {
+ System.out.println("Stop scrolling");
+ scrollButton.setCaption("Start scrolling");
+ scrollLock = true;
+ } else {
+ System.out.println("Start scrolling");
+ scrollButton.setCaption("Stop scrolling");
+ scrollLock = false;
+ }
+ }
+ });
+ buttons.addComponent(scrollButton);
+
+ container = new IndexedContainer();
+ container.addContainerProperty("sequenceNumber", String.class, null);
+ container.addContainerProperty("millis", String.class, null);
+ container.addContainerProperty("level", String.class, null);
+ container.addContainerProperty("message", String.class, null);
+
+ grid = new Grid(container);
+ grid.setWidth("100%");
+ grid.setImmediate(true);
+ grid.setSelectionMode(SelectionMode.SINGLE);
+ grid.addSelectionListener(new SelectionListener() {
+ @Override
+ public void select(final SelectionEvent event) {
+ if (grid.getSelectedRow() != null) {
+ disableScroll();
+ }
+ }
+ });
+
+ layout.addComponent(grid);
+ layout.setExpandRatio(grid, 1.0f);
+ }
+
+ protected void disableScroll() {
+ scrollLock = true;
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.java b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.java
new file mode 100644
index 0000000000..194a9a3acc
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.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.tests.components.grid;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.event.SelectionEvent;
+import com.vaadin.event.SelectionEvent.SelectionListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.SelectionMode;
+import com.vaadin.ui.VerticalSplitPanel;
+
+public class GridScrollToLineWhileResizing extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ final VerticalSplitPanel vsp = new VerticalSplitPanel();
+ vsp.setWidth(500, Unit.PIXELS);
+ vsp.setHeight(500, Unit.PIXELS);
+ vsp.setSplitPosition(100, Unit.PERCENTAGE);
+ addComponent(vsp);
+
+ IndexedContainer indexedContainer = new IndexedContainer();
+ indexedContainer.addContainerProperty("column1", String.class, "");
+
+ for (int i = 0; i < 100; i++) {
+ Item addItem = indexedContainer.addItem(i);
+ addItem.getItemProperty("column1").setValue("cell" + i);
+ }
+
+ final Grid grid = new Grid(indexedContainer);
+ grid.setSizeFull();
+
+ grid.setSelectionMode(SelectionMode.SINGLE);
+ grid.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void select(SelectionEvent event) {
+ vsp.setSplitPosition(50, Unit.PERCENTAGE);
+ grid.scrollTo(event.getSelected().iterator().next());
+ }
+ });
+
+ vsp.setFirstComponent(grid);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests scrollToLine while moving SplitPanel split position to resize the Grid on the same round-trip.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return null;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java
new file mode 100644
index 0000000000..aee1db7a85
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.grid;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.parallel.TestCategory;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+@TestCategory("grid")
+public class GridScrollToLineWhileResizingTest extends MultiBrowserTest {
+
+ @Test
+ public void testScrollToLineWorksWhileMovingSplitProgrammatically() {
+ openTestURL();
+
+ $(GridElement.class).first().getCell(21, 0).click();
+
+ List<WebElement> cells = findElements(By.className("v-grid-cell"));
+ boolean foundCell21 = false;
+ for (WebElement cell : cells) {
+ if ("cell21".equals(cell.getText())) {
+ foundCell21 = true;
+ }
+ }
+
+ assertTrue(foundCell21);
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java
new file mode 100644
index 0000000000..4d44eeb248
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.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.grid;
+
+import com.vaadin.server.ClassResource;
+import com.vaadin.server.Resource;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.tests.integration.FlagSeResource;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.renderers.ImageRenderer;
+
+public class GridWithBrokenRenderer extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final Grid grid = new Grid();
+ grid.addColumn("short", String.class);
+ grid.addColumn("icon", Resource.class);
+ grid.addColumn("country", String.class);
+
+ grid.getColumn("icon").setRenderer(new ImageRenderer());
+ addComponent(grid);
+
+ grid.addRow("FI", new ClassResource("fi.gif"), "Finland");
+ grid.addRow("SE", new FlagSeResource(), "Sweden");
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java
new file mode 100644
index 0000000000..011c8c92ce
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.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.components.grid;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class GridWithBrokenRendererTest extends SingleBrowserTest {
+
+ @Test
+ public void ensureRendered() {
+ openTestURL();
+ GridElement grid = $(GridElement.class).first();
+ assertRow(grid, 0, "FI", "", "Finland");
+ assertRow(grid, 1, "SE", "", "Sweden");
+ }
+
+ private void assertRow(GridElement grid, int row, String... texts) {
+ for (int column = 0; column < texts.length; column++) {
+ Assert.assertEquals("Cell " + row + "," + column, texts[column],
+ grid.getCell(row, column).getText());
+ }
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java
index b38178b156..2e86053ef3 100644
--- a/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java
@@ -43,6 +43,6 @@ public class JavaScriptRenderersTest extends MultiBrowserTest {
// Verify onbrowserevent
cell_1_1.click();
Assert.assertTrue(cell_1_1.getText().startsWith(
- "Clicked 1 with key 1 at"));
+ "Clicked 1 with key 2 at"));
}
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
index ef51cdf446..479ece71ca 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
@@ -29,6 +29,8 @@ import java.util.Random;
import com.vaadin.data.Container.Filter;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.sort.Sort;
import com.vaadin.data.sort.SortOrder;
@@ -48,7 +50,9 @@ import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.Field;
import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.CellDescriptionGenerator;
import com.vaadin.ui.Grid.CellReference;
import com.vaadin.ui.Grid.CellStyleGenerator;
import com.vaadin.ui.Grid.Column;
@@ -57,10 +61,15 @@ import com.vaadin.ui.Grid.ColumnReorderListener;
import com.vaadin.ui.Grid.ColumnVisibilityChangeEvent;
import com.vaadin.ui.Grid.ColumnVisibilityChangeListener;
import com.vaadin.ui.Grid.DetailsGenerator;
+import com.vaadin.ui.Grid.EditorCloseEvent;
+import com.vaadin.ui.Grid.EditorListener;
+import com.vaadin.ui.Grid.EditorMoveEvent;
+import com.vaadin.ui.Grid.EditorOpenEvent;
import com.vaadin.ui.Grid.FooterCell;
import com.vaadin.ui.Grid.HeaderCell;
import com.vaadin.ui.Grid.HeaderRow;
import com.vaadin.ui.Grid.MultiSelectionModel;
+import com.vaadin.ui.Grid.RowDescriptionGenerator;
import com.vaadin.ui.Grid.RowReference;
import com.vaadin.ui.Grid.RowStyleGenerator;
import com.vaadin.ui.Grid.SelectionMode;
@@ -123,6 +132,45 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
};
+ private RowDescriptionGenerator rowDescriptionGenerator = new RowDescriptionGenerator() {
+
+ @Override
+ public String getDescription(RowReference row) {
+ return "Row tooltip for row " + row.getItemId();
+ }
+ };
+
+ private CellDescriptionGenerator cellDescriptionGenerator = new CellDescriptionGenerator() {
+
+ @Override
+ public String getDescription(CellReference cell) {
+ if ("Column 0".equals(cell.getPropertyId())) {
+ return "Cell tooltip for row " + cell.getItemId()
+ + ", column 0";
+ } else {
+ return null;
+ }
+ }
+ };
+
+ private ItemClickListener editorOpeningItemClickListener = new ItemClickListener() {
+
+ @Override
+ public void itemClick(ItemClickEvent event) {
+ grid.editItem(event.getItemId());
+ }
+ };
+
+ private ValueChangeListener reactiveValueChanger = new ValueChangeListener() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public void valueChange(ValueChangeEvent event) {
+ Object id = grid.getEditedItemId();
+ grid.getContainerDataSource().getContainerProperty(id, "Column 2")
+ .setValue("Modified");
+ }
+ };
+
private ColumnReorderListener columnReorderListener = new ColumnReorderListener() {
@Override
@@ -273,6 +321,7 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
new NumberRenderer(new DecimalFormat("0,000.00",
DecimalFormatSymbols.getInstance(new Locale("fi",
"FI")))));
+
grid.getColumn(getColumnProperty(col++)).setRenderer(
new DateRenderer(new SimpleDateFormat("dd.MM.yy HH:mm")));
grid.getColumn(getColumnProperty(col++)).setRenderer(
@@ -362,49 +411,58 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
private void addFilterActions() {
- createClickAction("Column 1 starts with \"(23\"", "Filter",
- new Command<Grid, Void>() {
- @Override
- public void execute(Grid grid, Void value, Object data) {
- ds.addContainerFilter(new Filter() {
+ createBooleanAction("Column 1 starts with \"(23\"", "Filter", false,
+ new Command<Grid, Boolean>() {
+ Filter filter = new Filter() {
+ @Override
+ public boolean passesFilter(Object itemId, Item item) {
+ return item.getItemProperty("Column 1").getValue()
+ .toString().startsWith("(23");
+ }
- @Override
- public boolean passesFilter(Object itemId, Item item)
- throws UnsupportedOperationException {
- return item.getItemProperty("Column 1")
- .getValue().toString()
- .startsWith("(23");
- }
+ @Override
+ public boolean appliesToProperty(Object propertyId) {
+ return propertyId.equals("Column 1");
+ }
+ };
- @Override
- public boolean appliesToProperty(Object propertyId) {
- return propertyId.equals("Column 1");
- }
- });
+ @Override
+ public void execute(Grid grid, Boolean value, Object data) {
+ if (value) {
+ ds.addContainerFilter(filter);
+ } else {
+ ds.removeContainerFilter(filter);
+ }
}
- }, null);
+ });
- createClickAction("Add impassable filter", "Filter",
- new Command<Grid, Void>() {
- @Override
- public void execute(Grid c, Void value, Object data) {
- ds.addContainerFilter(new Filter() {
- @Override
- public boolean passesFilter(Object itemId, Item item)
- throws UnsupportedOperationException {
- return false;
- }
+ createBooleanAction("Impassable filter", "Filter", false,
+ new Command<Grid, Boolean>() {
+ Filter filter = new Filter() {
+ @Override
+ public boolean passesFilter(Object itemId, Item item) {
+ return false;
+ }
- @Override
- public boolean appliesToProperty(Object propertyId) {
- return true;
- }
- });
+ @Override
+ public boolean appliesToProperty(Object propertyId) {
+ return true;
+ }
+ };
+
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ if (value) {
+ ds.addContainerFilter(filter);
+ } else {
+ ds.removeContainerFilter(filter);
+ }
}
- }, null);
+ });
}
protected void createGridActions() {
+
LinkedHashMap<String, String> primaryStyleNames = new LinkedHashMap<String, String>();
primaryStyleNames.put("v-grid", "v-grid");
primaryStyleNames.put("v-escalator", "v-escalator");
@@ -594,6 +652,25 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
});
+ createBooleanAction("Row description generator", "State", false,
+ new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ c.setRowDescriptionGenerator(value ? rowDescriptionGenerator
+ : null);
+ }
+ });
+
+ createBooleanAction("Cell description generator", "State", false,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ c.setCellDescriptionGenerator(value ? cellDescriptionGenerator
+ : null);
+ }
+ });
+
LinkedHashMap<String, Integer> frozenOptions = new LinkedHashMap<String, Integer>();
for (int i = -1; i <= COLUMNS; i++) {
frozenOptions.put(String.valueOf(i), Integer.valueOf(i));
@@ -638,6 +715,39 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
});
+
+ createBooleanAction("EditorOpeningItemClickListener", "State", false,
+ new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ if (!value) {
+ c.removeItemClickListener(editorOpeningItemClickListener);
+ } else {
+ c.addItemClickListener(editorOpeningItemClickListener);
+ }
+ }
+
+ });
+ createBooleanAction("ReactiveValueChanger", "State", false,
+ new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ Field<?> targetField = grid.getEditorFieldGroup()
+ .getField("Column 0");
+ if (targetField != null) {
+ if (!value) {
+ targetField
+ .removeValueChangeListener(reactiveValueChanger);
+ } else {
+ targetField
+ .addValueChangeListener(reactiveValueChanger);
+ }
+ }
+ }
+
+ });
createBooleanAction("ColumnReorderListener", "State", false,
new Command<Grid, Boolean>() {
@@ -661,7 +771,6 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
}
});
-
createBooleanAction("Single select allow deselect", "State",
singleSelectAllowDeselect, new Command<Grid, Boolean>() {
@Override
@@ -683,6 +792,26 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
c.setColumnReorderingAllowed(value);
}
});
+
+ createClickAction("Select all", "State", new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ SelectionModel selectionModel = c.getSelectionModel();
+ if (selectionModel instanceof SelectionModel.Multi) {
+ ((SelectionModel.Multi) selectionModel).selectAll();
+ }
+ }
+ }, null);
+
+ createClickAction("Select none", "State", new Command<Grid, String>() {
+ @Override
+ public void execute(Grid c, String value, Object data) {
+ SelectionModel selectionModel = c.getSelectionModel();
+ if (selectionModel instanceof SelectionModel.Multi) {
+ ((SelectionModel.Multi) selectionModel).deselectAll();
+ }
+ }
+ }, null);
}
protected void createHeaderActions() {
@@ -1045,6 +1174,18 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
});
+
+ createClickAction("All columns expanding, Col 0 has max width of 30px",
+ "Columns", new Command<Grid, Boolean>() {
+
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ for (Column col : grid.getColumns()) {
+ col.setWidthUndefined();
+ }
+ grid.getColumns().get(0).setMaximumWidth(30);
+ }
+ }, null);
}
private static String getColumnProperty(int c) {
@@ -1218,6 +1359,14 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
}
});
+ createBooleanAction("Buffered mode", "Editor", true,
+ new Command<Grid, Boolean>() {
+ @Override
+ public void execute(Grid c, Boolean value, Object data) {
+ c.setEditorBuffered(value);
+ }
+ });
+
createClickAction("Edit item 5", "Editor", new Command<Grid, String>() {
@Override
public void execute(Grid c, String value, Object data) {
@@ -1265,6 +1414,30 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
c.setEditorCancelCaption("ʃǝɔuɐↃ");
}
}, null);
+
+ createClickAction("Add editor state listener", "Editor",
+ new Command<Grid, String>() {
+ @Override
+ public void execute(Grid grid, String value, Object data) {
+ grid.addEditorListener(new EditorListener() {
+ @Override
+ public void editorOpened(EditorOpenEvent e) {
+ log("Editor opened");
+ }
+
+ @Override
+ public void editorMoved(EditorMoveEvent e) {
+ log("Editor moved");
+ }
+
+ @Override
+ public void editorClosed(EditorCloseEvent e) {
+ log("Editor closed");
+ }
+ });
+ }
+ }, null);
+
}
@SuppressWarnings("boxing")
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java
index a307aaca16..a169e701c0 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java
@@ -823,6 +823,7 @@ public class GridColumnHidingTest extends GridBasicClientFeaturesTest {
@Test
public void testColumnHiding_detailsRowIsOpen_renderedCorrectly() {
+ selectMenuPath("Component", "Row details", "Set generator");
selectMenuPath("Component", "Row details", "Toggle details for...",
"Row 1");
assertColumnHeaderOrder(0, 1, 2, 3, 4);
@@ -870,7 +871,10 @@ public class GridColumnHidingTest extends GridBasicClientFeaturesTest {
selectMenuPath("Component", "Columns", "Column 0", "Hidable");
getSidebarOpenButton().click();
verifySidebarOpened();
- findElement(By.className("v-app")).click();
+ // Click somewhere far from Grid.
+ new Actions(getDriver())
+ .moveToElement(findElement(By.className("v-app")), 600, 600)
+ .click().perform();
verifySidebarClosed();
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java
new file mode 100644
index 0000000000..ed712361a6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.grid.basicfeatures;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+public class GridDescriptionGeneratorTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testCellDescription() {
+ openTestURL();
+ selectMenuPath("Component", "State", "Cell description generator");
+
+ getGridElement().getCell(1, 0).showTooltip();
+ String tooltipText = findElement(By.className("v-tooltip-text"))
+ .getText();
+ assertEquals("Tooltip text", "Cell tooltip for row 1, column 0",
+ tooltipText);
+
+ getGridElement().getCell(1, 1).showTooltip();
+ assertTrue("Tooltip should not be present in cell (1, 1) ",
+ findElement(By.className("v-tooltip-text")).getText().isEmpty());
+ }
+
+ @Test
+ public void testRowDescription() {
+ openTestURL();
+ selectMenuPath("Component", "State", "Row description generator");
+
+ getGridElement().getCell(5, 3).showTooltip();
+ String tooltipText = findElement(By.className("v-tooltip-text"))
+ .getText();
+ assertEquals("Tooltip text", "Row tooltip for row 5", tooltipText);
+
+ getGridElement().getCell(15, 3).showTooltip();
+ tooltipText = findElement(By.className("v-tooltip-text")).getText();
+ assertEquals("Tooltip text", "Row tooltip for row 15", tooltipText);
+ }
+
+ @Test
+ public void testRowAndCellDescription() {
+ openTestURL();
+ selectMenuPath("Component", "State", "Row description generator");
+ selectMenuPath("Component", "State", "Cell description generator");
+
+ getGridElement().getCell(5, 0).showTooltip();
+ String tooltipText = findElement(By.className("v-tooltip-text"))
+ .getText();
+ assertEquals("Tooltip text", "Cell tooltip for row 5, column 0",
+ tooltipText);
+
+ getGridElement().getCell(5, 3).showTooltip();
+ tooltipText = findElement(By.className("v-tooltip-text")).getText();
+ assertEquals("Tooltip text", "Row tooltip for row 5", tooltipText);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java
index 88158c7f6f..01e7e52923 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java
@@ -35,8 +35,8 @@ import com.vaadin.shared.ui.grid.ScrollDestination;
import com.vaadin.testbench.By;
import com.vaadin.testbench.ElementQuery;
import com.vaadin.testbench.TestBenchElement;
-import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest;
+import com.vaadin.tests.tb3.newelements.FixedNotificationElement;
public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
@@ -59,14 +59,10 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
getGridElement().getDetails(1));
}
- @Test
- public void nullRendererShowsDetailsPlaceholder() {
+ @Test(expected = NoSuchElementException.class)
+ public void nullRendererDoesNotShowDetailsPlaceholder() {
toggleDetailsFor(1);
- TestBenchElement details = getGridElement().getDetails(1);
- assertNotNull("details for row 1 should not exist at the start",
- details);
- assertTrue("details should've been empty for null renderer", details
- .getText().isEmpty());
+ getGridElement().getDetails(1);
}
@Test
@@ -79,14 +75,12 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
details.getText().startsWith("Row: 1."));
}
- @Test
- public void openDetailsThenAppyRenderer() {
+ @Test(expected = NoSuchElementException.class)
+ public void openDetailsThenAppyRendererShouldNotShowDetails() {
toggleDetailsFor(1);
selectMenuPath(SET_GENERATOR);
- TestBenchElement details = getGridElement().getDetails(1);
- assertTrue("Unexpected details content",
- details.getText().startsWith("Row: 1."));
+ getGridElement().getDetails(1);
}
@Test
@@ -112,12 +106,12 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
@Test
public void errorUpdaterShowsErrorNotification() {
assertFalse("No notifications should've been at the start",
- $(NotificationElement.class).exists());
+ $(FixedNotificationElement.class).exists());
- toggleDetailsFor(1);
selectMenuPath(SET_FAULTY_GENERATOR);
+ toggleDetailsFor(1);
- ElementQuery<NotificationElement> notification = $(NotificationElement.class);
+ ElementQuery<FixedNotificationElement> notification = $(FixedNotificationElement.class);
assertTrue("Was expecting an error notification here",
notification.exists());
notification.first().close();
@@ -126,13 +120,25 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
getGridElement().getDetails(1).getText());
}
- @Test
- public void updaterStillWorksAfterError() {
+ @Test(expected = NoSuchElementException.class)
+ public void detailsClosedWhenResettingGenerator() {
+
+ selectMenuPath(SET_GENERATOR);
toggleDetailsFor(1);
selectMenuPath(SET_FAULTY_GENERATOR);
- $(NotificationElement.class).first().close();
+ getGridElement().getDetails(1);
+ }
+
+ @Test
+ public void settingNewGeneratorStillWorksAfterError() {
+ selectMenuPath(SET_FAULTY_GENERATOR);
+ toggleDetailsFor(1);
+ $(FixedNotificationElement.class).first().close();
+ toggleDetailsFor(1);
+
selectMenuPath(SET_GENERATOR);
+ toggleDetailsFor(1);
assertNotEquals(
"New details should've been generated even after error", "",
@@ -184,6 +190,7 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
@Test
public void rowElementClassNames() {
+ selectMenuPath(SET_GENERATOR);
toggleDetailsFor(0);
toggleDetailsFor(1);
@@ -196,25 +203,28 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
@Test
public void scrollDownToRowWithDetails() {
+ selectMenuPath(SET_GENERATOR);
toggleDetailsFor(100);
scrollToRow(100, ScrollDestination.ANY);
- Range validScrollRange = Range.between(1700, 1715);
+ Range validScrollRange = Range.between(1691, 1706);
assertTrue(validScrollRange.contains(getGridVerticalScrollPos()));
}
@Test
public void scrollUpToRowWithDetails() {
+ selectMenuPath(SET_GENERATOR);
toggleDetailsFor(100);
scrollGridVerticallyTo(999999);
scrollToRow(100, ScrollDestination.ANY);
- Range validScrollRange = Range.between(1990, 2010);
+ Range validScrollRange = Range.between(1981, 2001);
assertTrue(validScrollRange.contains(getGridVerticalScrollPos()));
}
@Test
public void cannotScrollBeforeTop() {
+ selectMenuPath(SET_GENERATOR);
toggleDetailsFor(1);
scrollToRow(0, ScrollDestination.END);
assertEquals(0, getGridVerticalScrollPos());
@@ -222,10 +232,11 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest {
@Test
public void cannotScrollAfterBottom() {
+ selectMenuPath(SET_GENERATOR);
toggleDetailsFor(999);
scrollToRow(999, ScrollDestination.START);
- Range expectedRange = Range.withLength(19680, 20);
+ Range expectedRange = Range.withLength(19671, 20);
assertTrue(expectedRange.contains(getGridVerticalScrollPos()));
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java
index f437589a39..0dd137db48 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java
@@ -81,9 +81,19 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest {
getGridElement().getCell(4, 0).doubleClick();
assertNotNull(getEditor());
- getCancelButton().click();
+ // Move focus to the third input field
+ getEditor().findElements(By.className("gwt-TextBox")).get(2).click();
+
+ // Press save button
+ getSaveButton().click();
+
+ // Make sure the editor went away
assertNull(getEditor());
+ // Check that focus has moved to cell 4,2 - the last one that was
+ // focused in Editor
+ assertTrue(getGridElement().getCell(4, 2).isFocused());
+
// Disable editor
selectMenuPath("Component", "Editor", "Enabled");
@@ -134,14 +144,16 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest {
@Test
public void testWithSelectionColumn() throws Exception {
selectMenuPath("Component", "State", "Selection mode", "multi");
+ selectMenuPath("Component", "State", "Frozen column count",
+ "-1 columns");
selectMenuPath(EDIT_ROW_5);
- WebElement editorCells = findElement(By
- .className("v-grid-editor-cells"));
+ WebElement editorCells = findElements(
+ By.className("v-grid-editor-cells")).get(1);
List<WebElement> selectorDivs = editorCells.findElements(By
.cssSelector("div"));
- assertTrue("selector column cell should've been empty", selectorDivs
+ assertFalse("selector column cell should've had contents", selectorDivs
.get(0).getAttribute("innerHTML").isEmpty());
assertFalse("normal column cell shoul've had contents", selectorDivs
.get(1).getAttribute("innerHTML").isEmpty());
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java
new file mode 100644
index 0000000000..7f19559aec
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.grid.basicfeatures.server;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+public class GridColumnMaxWidthTest extends GridBasicFeaturesTest {
+
+ @Test
+ public void testMaxWidthAffectsColumnWidth() {
+ setDebug(true);
+ openTestURL();
+
+ selectMenuPath("Component", "Columns",
+ "All columns expanding, Col 0 has max width of 30px");
+
+ assertEquals("Column 0 did not obey max width of 30px.", 30,
+ getGridElement().getCell(0, 0).getSize().getWidth());
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java
index 4ea64073f3..a9ab7027db 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java
@@ -22,7 +22,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
@@ -59,7 +58,7 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
openTestURL();
}
- @Test
+ @Test(expected = NoSuchElementException.class)
public void openVisibleDetails() {
try {
getGridElement().getDetails(0);
@@ -68,8 +67,7 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
// expected
}
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
- assertNotNull("details should've opened", getGridElement()
- .getDetails(0));
+ getGridElement().getDetails(0);
}
@Test(expected = NoSuchElementException.class)
@@ -99,6 +97,7 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
@Test
public void openDetailsOutsideOfActiveRange() throws InterruptedException {
getGridElement().scroll(10000);
+ selectMenuPath(DETAILS_GENERATOR_WATCHING);
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
getGridElement().scroll(0);
Thread.sleep(50);
@@ -196,14 +195,11 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
assertEquals("Two", getGridElement().getDetails(0).getText());
}
- @Ignore("This use case is not currently supported by Grid. If the detail "
- + "is out of view, the component is detached from the UI and a "
- + "new instance is generated when scrolled back. Support will "
- + "maybe be incorporated at a later time")
@Test
public void hierarchyChangesWorkInDetailsWhileOutOfView() {
selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL);
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
+ assertEquals("One", getGridElement().getDetails(0).getText());
scrollGridVerticallyTo(10000);
selectMenuPath(CHANGE_HIERARCHY);
scrollGridVerticallyTo(0);
@@ -219,13 +215,15 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
@Test
public void swappingDetailsGenerators_shownDetails() {
+ selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL);
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
- assertTrue("Details should be empty at the start", getGridElement()
- .getDetails(0).getText().isEmpty());
+ assertTrue("Details should contain 'One' at first", getGridElement()
+ .getDetails(0).getText().contains("One"));
selectMenuPath(DETAILS_GENERATOR_WATCHING);
- assertFalse("Details should not be empty after swapping generator",
- getGridElement().getDetails(0).getText().isEmpty());
+ assertFalse(
+ "Details should contain 'Watching' after swapping generator",
+ getGridElement().getDetails(0).getText().contains("Watching"));
}
@Test
@@ -239,6 +237,7 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
@Test
public void swappingDetailsGenerators_whileDetailsScrolledOut_showAfter() {
scrollGridVerticallyTo(1000);
+ selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL);
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
selectMenuPath(DETAILS_GENERATOR_WATCHING);
scrollGridVerticallyTo(0);
@@ -250,6 +249,7 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
@Test
public void swappingDetailsGenerators_whileDetailsScrolledOut_showBefore() {
+ selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL);
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
selectMenuPath(DETAILS_GENERATOR_WATCHING);
scrollGridVerticallyTo(1000);
@@ -261,6 +261,7 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
@Test
public void swappingDetailsGenerators_whileDetailsScrolledOut_showBeforeAndAfter() {
+ selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL);
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
selectMenuPath(DETAILS_GENERATOR_WATCHING);
scrollGridVerticallyTo(1000);
@@ -272,24 +273,6 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest {
}
@Test
- public void nullDetailComponentToggling() {
- selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
- selectMenuPath(DETAILS_GENERATOR_WATCHING);
- selectMenuPath(DETAILS_GENERATOR_NULL);
-
- try {
- assertTrue("Details should be empty with null component",
- getGridElement().getDetails(0).getText().isEmpty());
- } catch (NoSuchElementException e) {
- fail("Expected to find a details row with empty content");
- }
-
- selectMenuPath(DETAILS_GENERATOR_WATCHING);
- assertFalse("Details should be not empty with details component",
- getGridElement().getDetails(0).getText().isEmpty());
- }
-
- @Test
public void noAssertErrorsOnEmptyDetailsAndScrollDown() {
selectMenuPath(OPEN_FIRST_ITEM_DETAILS);
scrollGridVerticallyTo(500);
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java
new file mode 100644
index 0000000000..57f4b877df
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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.grid.basicfeatures.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.shared.ui.grid.GridConstants;
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+import com.vaadin.testbench.elements.GridElement.GridEditorElement;
+import com.vaadin.testbench.elements.NotificationElement;
+
+public class GridEditorBufferedTest extends GridEditorTest {
+
+ @Override
+ @Before
+ public void setUp() {
+ super.setUp();
+ }
+
+ @Test
+ public void testSave() {
+ selectMenuPath(EDIT_ITEM_100);
+
+ WebElement textField = getEditorWidgets().get(0);
+
+ textField.click();
+
+ textField.sendKeys(" changed");
+
+ WebElement saveButton = getEditor().findElement(
+ By.className("v-grid-editor-save"));
+
+ saveButton.click();
+
+ assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
+ .getText());
+ }
+
+ @Test
+ public void testProgrammaticSave() {
+ selectMenuPath(EDIT_ITEM_100);
+
+ WebElement textField = getEditorWidgets().get(0);
+
+ textField.click();
+
+ textField.sendKeys(" changed");
+
+ selectMenuPath("Component", "Editor", "Save");
+
+ assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
+ .getText());
+ }
+
+ @Test
+ public void testInvalidEdition() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertFalse(logContainsText("Exception occured, java.lang.IllegalStateException"));
+
+ GridEditorElement editor = getGridElement().getEditor();
+
+ assertFalse(
+ "Field 7 should not have been marked with an error before error",
+ editor.isFieldErrorMarked(7));
+
+ WebElement intField = editor.getField(7);
+ intField.clear();
+ intField.sendKeys("banana phone");
+ editor.save();
+
+ assertEquals("Column 7: Could not convert value to Integer",
+ editor.getErrorMessage());
+ assertTrue("Field 7 should have been marked with an error after error",
+ editor.isFieldErrorMarked(7));
+ editor.cancel();
+
+ selectMenuPath(EDIT_ITEM_100);
+ assertFalse("Exception should not exist",
+ isElementPresent(NotificationElement.class));
+ assertEquals("There should be no editor error message", null,
+ getGridElement().getEditor().getErrorMessage());
+ }
+
+ @Test
+ public void testEditorInDisabledGrid() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+
+ selectMenuPath("Component", "State", "Enabled");
+ assertEditorOpen();
+
+ GridEditorElement editor = getGridElement().getEditor();
+ editor.save();
+ assertEditorOpen();
+
+ editor.cancel();
+ assertEditorOpen();
+
+ selectMenuPath("Component", "State", "Enabled");
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testCaptionChange() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEquals("Save button caption should've been \""
+ + GridConstants.DEFAULT_SAVE_CAPTION + "\" to begin with",
+ GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
+ assertEquals("Cancel button caption should've been \""
+ + GridConstants.DEFAULT_CANCEL_CAPTION + "\" to begin with",
+ GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
+ .getText());
+
+ selectMenuPath("Component", "Editor", "Change save caption");
+ assertNotEquals(
+ "Save button caption should've changed while editor is open",
+ GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
+
+ getCancelButton().click();
+
+ selectMenuPath("Component", "Editor", "Change cancel caption");
+ selectMenuPath(EDIT_ITEM_5);
+ assertNotEquals(
+ "Cancel button caption should've changed while editor is closed",
+ GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
+ .getText());
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void testVerticalScrollLocking() {
+ selectMenuPath(EDIT_ITEM_5);
+ getGridElement().getCell(200, 0);
+ }
+
+ @Test
+ public void testScrollDisabledOnProgrammaticOpen() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ selectMenuPath(EDIT_ITEM_5);
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testScrollDisabledOnMouseOpen() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ new Actions(getDriver()).doubleClick(cell_5_0).perform();
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testScrollDisabledOnKeyboardOpen() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ cell_5_0.click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ scrollGridVerticallyTo(100);
+ assertEquals(
+ "Grid shouldn't scroll vertically while editing in buffered mode",
+ originalScrollPos, getGridVerticalScrollPos());
+ }
+
+ @Test
+ public void testMouseOpeningClosing() {
+
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorOpen();
+
+ getCancelButton().click();
+ assertEditorClosed();
+
+ selectMenuPath(TOGGLE_EDIT_ENABLED);
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorClosed();
+ }
+
+ @Test
+ public void testMouseOpeningDisabledWhenOpen() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ getGridElement().getCell(4, 0).doubleClick();
+
+ assertEquals("Editor should still edit row 5", "(5, 0)",
+ getEditorWidgets().get(0).getAttribute("value"));
+ }
+
+ @Test
+ public void testKeyboardOpeningDisabledWhenOpen() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ new Actions(getDriver()).click(getGridElement().getCell(4, 0))
+ .sendKeys(Keys.ENTER).perform();
+
+ assertEquals("Editor should still edit row 5", "(5, 0)",
+ getEditorWidgets().get(0).getAttribute("value"));
+ }
+
+ @Test
+ public void testProgrammaticOpeningDisabledWhenOpen() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+ assertEquals("Editor should edit row 5", "(5, 0)", getEditorWidgets()
+ .get(0).getAttribute("value"));
+
+ selectMenuPath(EDIT_ITEM_100);
+ boolean thrown = logContainsText("Exception occured, java.lang.IllegalStateException");
+ assertTrue("IllegalStateException thrown", thrown);
+
+ assertEditorOpen();
+ assertEquals("Editor should still edit row 5", "(5, 0)",
+ getEditorWidgets().get(0).getAttribute("value"));
+ }
+
+ @Test
+ public void testUserSortDisabledWhenOpen() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ getGridElement().getHeaderCell(0, 0).click();
+
+ assertEditorOpen();
+ assertEquals("(2, 0)", getGridElement().getCell(2, 0).getText());
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java
index 0c39b3e509..0cba2ce34b 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java
@@ -17,7 +17,6 @@ package com.vaadin.tests.components.grid.basicfeatures.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -28,24 +27,26 @@ import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
-import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
-import com.vaadin.shared.ui.grid.GridConstants;
+import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elements.GridElement.GridCellElement;
import com.vaadin.testbench.elements.GridElement.GridEditorElement;
-import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures;
import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
-public class GridEditorTest extends GridBasicFeaturesTest {
+public abstract class GridEditorTest extends GridBasicFeaturesTest {
- private static final String[] EDIT_ITEM_5 = new String[] { "Component",
+ protected static final By BY_EDITOR_CANCEL = By
+ .className("v-grid-editor-cancel");
+ protected static final By BY_EDITOR_SAVE = By
+ .className("v-grid-editor-save");
+ protected static final String[] EDIT_ITEM_5 = new String[] { "Component",
"Editor", "Edit item 5" };
- private static final String[] EDIT_ITEM_100 = new String[] { "Component",
+ protected static final String[] EDIT_ITEM_100 = new String[] { "Component",
"Editor", "Edit item 100" };
- private static final String[] TOGGLE_EDIT_ENABLED = new String[] {
+ protected static final String[] TOGGLE_EDIT_ENABLED = new String[] {
"Component", "Editor", "Enabled" };
@Before
@@ -88,26 +89,6 @@ public class GridEditorTest extends GridBasicFeaturesTest {
assertEditorOpen();
}
- @Test(expected = NoSuchElementException.class)
- public void testVerticalScrollLocking() {
- selectMenuPath(EDIT_ITEM_5);
- getGridElement().getCell(200, 0);
- }
-
- @Test
- public void testMouseOpeningClosing() {
-
- getGridElement().getCell(4, 0).doubleClick();
- assertEditorOpen();
-
- getCancelButton().click();
- assertEditorClosed();
-
- selectMenuPath(TOGGLE_EDIT_ENABLED);
- getGridElement().getCell(4, 0).doubleClick();
- assertEditorClosed();
- }
-
@Test
public void testKeyboardOpeningClosing() {
@@ -141,237 +122,180 @@ public class GridEditorTest extends GridBasicFeaturesTest {
assertEquals("<b>100</b>", widgets.get(8).getAttribute("value"));
}
- @Test
- public void testSave() {
- selectMenuPath(EDIT_ITEM_100);
-
- WebElement textField = getEditorWidgets().get(0);
-
- textField.click();
-
- textField.sendKeys(" changed");
+ protected void assertEditorOpen() {
+ assertEquals("Unexpected number of widgets",
+ GridBasicFeatures.EDITABLE_COLUMNS, getEditorWidgets().size());
+ }
- WebElement saveButton = getEditor().findElement(
- By.className("v-grid-editor-save"));
+ protected void assertEditorClosed() {
+ assertNull("Editor is supposed to be closed", getEditor());
+ }
- saveButton.click();
+ protected List<WebElement> getEditorWidgets() {
+ assertNotNull("Editor is supposed to be open", getEditor());
+ return getEditor().findElements(By.className("v-textfield"));
- assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
- .getText());
}
@Test
- public void testProgrammaticSave() {
- selectMenuPath(EDIT_ITEM_100);
-
- WebElement textField = getEditorWidgets().get(0);
+ public void testFocusOnMouseOpen() {
- textField.click();
+ GridCellElement cell = getGridElement().getCell(4, 2);
- textField.sendKeys(" changed");
+ cell.doubleClick();
- selectMenuPath("Component", "Editor", "Save");
+ WebElement focused = getFocusedElement();
- assertEquals("(100, 0) changed", getGridElement().getCell(100, 0)
- .getText());
+ assertEquals("", "input", focused.getTagName());
+ assertEquals("", cell.getText(), focused.getAttribute("value"));
}
@Test
- public void testCaptionChange() {
- selectMenuPath(EDIT_ITEM_5);
- assertEquals("Save button caption should've been \""
- + GridConstants.DEFAULT_SAVE_CAPTION + "\" to begin with",
- GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
- assertEquals("Cancel button caption should've been \""
- + GridConstants.DEFAULT_CANCEL_CAPTION + "\" to begin with",
- GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
- .getText());
-
- selectMenuPath("Component", "Editor", "Change save caption");
- assertNotEquals(
- "Save button caption should've changed while editor is open",
- GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText());
-
- getCancelButton().click();
-
- selectMenuPath("Component", "Editor", "Change cancel caption");
- selectMenuPath(EDIT_ITEM_5);
- assertNotEquals(
- "Cancel button caption should've changed while editor is closed",
- GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton()
- .getText());
- }
+ public void testFocusOnKeyboardOpen() {
- private void assertEditorOpen() {
- assertNotNull("Editor is supposed to be open", getEditor());
- assertEquals("Unexpected number of widgets",
- GridBasicFeatures.EDITABLE_COLUMNS, getEditorWidgets().size());
- }
+ GridCellElement cell = getGridElement().getCell(4, 2);
- private void assertEditorClosed() {
- assertNull("Editor is supposed to be closed", getEditor());
- }
+ cell.click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
- private List<WebElement> getEditorWidgets() {
- assertNotNull(getEditor());
- return getEditor().findElements(By.className("v-textfield"));
+ WebElement focused = getFocusedElement();
+ assertEquals("", "input", focused.getTagName());
+ assertEquals("", cell.getText(), focused.getAttribute("value"));
}
@Test
- public void testInvalidEdition() {
- selectMenuPath(EDIT_ITEM_5);
- assertFalse(logContainsText("Exception occured, java.lang.IllegalStateException"));
+ public void testFocusOnProgrammaticOpenOnItemClick() {
+ selectMenuPath("Component", "State", "EditorOpeningItemClickListener");
- GridEditorElement editor = getGridElement().getEditor();
-
- assertFalse(
- "Field 7 should not have been marked with an error before error",
- editor.isFieldErrorMarked(7));
+ GridCellElement cell = getGridElement().getCell(4, 2);
- WebElement intField = editor.getField(7);
- intField.clear();
- intField.sendKeys("banana phone");
- editor.save();
+ cell.click();
- assertEquals("Column 7: Could not convert value to Integer",
- editor.getErrorMessage());
- assertTrue("Field 7 should have been marked with an error after error",
- editor.isFieldErrorMarked(7));
- editor.cancel();
+ WebElement focused = getFocusedElement();
- selectMenuPath(EDIT_ITEM_100);
- assertFalse("Exception should not exist",
- isElementPresent(NotificationElement.class));
- assertEquals("There should be no editor error message", null,
- getGridElement().getEditor().getErrorMessage());
+ assertEquals("", "input", focused.getTagName());
+ assertEquals("", cell.getText(), focused.getAttribute("value"));
}
@Test
- public void testNoScrollAfterProgrammaticOpen() {
- int originalScrollPos = getGridVerticalScrollPos();
+ public void testNoFocusOnProgrammaticOpen() {
selectMenuPath(EDIT_ITEM_5);
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
+ WebElement focused = getFocusedElement();
+
+ assertEquals("Focus should remain in the menu", "menu",
+ focused.getAttribute("id"));
}
@Test
- public void testNoScrollAfterMouseOpen() {
- int originalScrollPos = getGridVerticalScrollPos();
+ public void testUneditableColumn() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
- GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
- new Actions(getDriver()).doubleClick(cell_5_0).perform();
+ GridEditorElement editor = getGridElement().getEditor();
+ assertFalse("Uneditable column should not have an editor widget",
+ editor.isEditable(3));
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
- }
+ String classNames = editor
+ .findElements(By.className("v-grid-editor-cells")).get(1)
+ .findElements(By.xpath("./div")).get(3).getAttribute("class");
- @Test
- public void testNoScrollAfterKeyboardOpen() {
- int originalScrollPos = getGridVerticalScrollPos();
+ assertTrue("Noneditable cell should contain not-editable classname",
+ classNames.contains("not-editable"));
- GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
- cell_5_0.click();
- new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ assertTrue("Noneditable cell should contain v-grid-cell classname",
+ classNames.contains("v-grid-cell"));
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
+ assertNoErrorNotifications();
}
@Test
- public void testEditorInDisabledGrid() {
- int originalScrollPos = getGridVerticalScrollPos();
+ public void testNoOpenFromHeaderOrFooter() {
+ selectMenuPath("Component", "Footer", "Visible");
- selectMenuPath(EDIT_ITEM_5);
- assertEditorOpen();
+ getGridElement().getHeaderCell(0, 0).doubleClick();
+ assertEditorClosed();
- selectMenuPath("Component", "State", "Enabled");
- assertEditorOpen();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ assertEditorClosed();
- GridEditorElement editor = getGridElement().getEditor();
- editor.save();
- assertEditorOpen();
+ getGridElement().getFooterCell(0, 0).doubleClick();
+ assertEditorClosed();
- editor.cancel();
- assertEditorOpen();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ assertEditorClosed();
+ }
- selectMenuPath("Component", "State", "Enabled");
+ public void testEditorMoveOnResize() {
+ selectMenuPath("Component", "Size", "Height", "500px");
+ getGridElement().getCell(22, 0).doubleClick();
+ assertEditorOpen();
- scrollGridVerticallyTo(100);
- assertEquals("Grid shouldn't scroll vertically while editing",
- originalScrollPos, getGridVerticalScrollPos());
- }
+ GridEditorElement editor = getGridElement().getEditor();
+ TestBenchElement tableWrapper = getGridElement().getTableWrapper();
- @Test
- public void testFocusOnMouseOpen() {
+ int tableWrapperBottom = tableWrapper.getLocation().getY()
+ + tableWrapper.getSize().getHeight();
+ int editorBottom = editor.getLocation().getY()
+ + editor.getSize().getHeight();
- GridCellElement cell = getGridElement().getCell(4, 2);
+ assertTrue("Editor should not be initially outside grid",
+ tableWrapperBottom - editorBottom <= 2);
- cell.doubleClick();
+ selectMenuPath("Component", "Size", "Height", "300px");
+ assertEditorOpen();
- WebElement focused = getFocusedElement();
+ tableWrapperBottom = tableWrapper.getLocation().getY()
+ + tableWrapper.getSize().getHeight();
+ editorBottom = editor.getLocation().getY()
+ + editor.getSize().getHeight();
- assertEquals("", "input", focused.getTagName());
- assertEquals("", cell.getText(), focused.getAttribute("value"));
+ assertTrue("Editor should not be outside grid after resize",
+ tableWrapperBottom - editorBottom <= 2);
}
- @Test
- public void testFocusOnKeyboardOpen() {
+ public void testEditorDoesNotMoveOnResizeIfNotNeeded() {
+ selectMenuPath("Component", "Size", "Height", "500px");
- GridCellElement cell = getGridElement().getCell(4, 2);
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
- cell.click();
- new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+ GridEditorElement editor = getGridElement().getEditor();
- WebElement focused = getFocusedElement();
+ int editorPos = editor.getLocation().getY();
- assertEquals("", "input", focused.getTagName());
- assertEquals("", cell.getText(), focused.getAttribute("value"));
+ selectMenuPath("Component", "Size", "Height", "300px");
+ assertEditorOpen();
+
+ assertTrue("Editor should not have moved due to resize",
+ editorPos == editor.getLocation().getY());
}
@Test
- public void testNoFocusOnProgrammaticOpen() {
-
+ public void testEditorClosedOnSort() {
selectMenuPath(EDIT_ITEM_5);
- WebElement focused = getFocusedElement();
-
- assertEquals("Focus should remain in the menu", "menu",
- focused.getAttribute("id"));
- }
+ selectMenuPath("Component", "State", "Sort by column", "Column 0, ASC");
- @Override
- protected WebElement getFocusedElement() {
- return (WebElement) executeScript("return document.activeElement;");
+ assertEditorClosed();
}
@Test
- public void testUneditableColumn() {
+ public void testEditorClosedOnFilter() {
selectMenuPath(EDIT_ITEM_5);
- assertEditorOpen();
- GridEditorElement editor = getGridElement().getEditor();
- assertFalse("Uneditable column should not have an editor widget",
- editor.isEditable(3));
- assertEquals(
- "Not editable cell did not contain correct classname",
- "not-editable",
- editor.findElement(By.className("v-grid-editor-cells"))
- .findElements(By.xpath("./div")).get(3)
- .getAttribute("class"));
+ selectMenuPath("Component", "Filter", "Column 1 starts with \"(23\"");
+ assertEditorClosed();
}
- private WebElement getSaveButton() {
- return getDriver().findElement(By.className("v-grid-editor-save"));
+ protected WebElement getSaveButton() {
+ return getDriver().findElement(BY_EDITOR_SAVE);
}
- private WebElement getCancelButton() {
- return getDriver().findElement(By.className("v-grid-editor-cancel"));
+ protected WebElement getCancelButton() {
+ return getDriver().findElement(BY_EDITOR_CANCEL);
}
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java
new file mode 100644
index 0000000000..08094b57e3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java
@@ -0,0 +1,223 @@
+/*
+ * 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.grid.basicfeatures.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+
+public class GridEditorUnbufferedTest extends GridEditorTest {
+
+ private static final String[] TOGGLE_EDITOR_BUFFERED = new String[] {
+ "Component", "Editor", "Buffered mode" };
+ private static final String[] CANCEL_EDIT = new String[] { "Component",
+ "Editor", "Cancel edit" };
+
+ @Override
+ @Before
+ public void setUp() {
+ super.setUp();
+ selectMenuPath(TOGGLE_EDITOR_BUFFERED);
+ }
+
+ @Test
+ public void testEditorShowsNoButtons() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ assertEditorOpen();
+
+ assertFalse("Save button should not be visible in unbuffered mode.",
+ isElementPresent(BY_EDITOR_SAVE));
+
+ assertFalse("Cancel button should not be visible in unbuffered mode.",
+ isElementPresent(BY_EDITOR_CANCEL));
+ }
+
+ @Test
+ public void testToggleEditorUnbufferedWhileOpen() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+ selectMenuPath(TOGGLE_EDITOR_BUFFERED);
+ boolean thrown = logContainsText("Exception occured, java.lang.IllegalStateException");
+ assertTrue("IllegalStateException thrown", thrown);
+ }
+
+ @Test
+ public void testEditorMove() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ assertEditorOpen();
+
+ String firstFieldValue = getEditorWidgets().get(0)
+ .getAttribute("value");
+ assertEquals("Editor should be at row 5", "(5, 0)", firstFieldValue);
+
+ getGridElement().getCell(10, 0).click();
+ firstFieldValue = getEditorWidgets().get(0).getAttribute("value");
+
+ assertEquals("Editor should be at row 10", "(10, 0)", firstFieldValue);
+ }
+
+ @Test
+ public void testValidationErrorPreventsMove() {
+ // Because of "out of view" issues, we need to move this for easy access
+ selectMenuPath("Component", "Columns", "Column 7", "Column 7 Width",
+ "50px");
+ for (int i = 0; i < 6; ++i) {
+ selectMenuPath("Component", "Columns", "Column 7", "Move left");
+ }
+
+ selectMenuPath(EDIT_ITEM_5);
+
+ getEditorWidgets().get(1).click();
+ getEditorWidgets().get(1).sendKeys("not a number");
+
+ getGridElement().getCell(10, 0).click();
+
+ assertEquals("Editor should not move from row 5", "(5, 0)",
+ getEditorWidgets().get(0).getAttribute("value"));
+ }
+
+ @Test
+ public void testErrorMessageWrapperHidden() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ assertEditorOpen();
+
+ WebElement editorFooter = getEditor().findElement(
+ By.className("v-grid-editor-footer"));
+
+ assertTrue("Editor footer should not be visible when there's no error",
+ editorFooter.getCssValue("display").equalsIgnoreCase("none"));
+ }
+
+ @Test
+ public void testScrollEnabledOnProgrammaticOpen() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ selectMenuPath(EDIT_ITEM_5);
+
+ scrollGridVerticallyTo(100);
+ assertGreater(
+ "Grid should scroll vertically while editing in unbuffered mode",
+ getGridVerticalScrollPos(), originalScrollPos);
+ }
+
+ @Test
+ public void testScrollEnabledOnMouseOpen() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ new Actions(getDriver()).doubleClick(cell_5_0).perform();
+
+ scrollGridVerticallyTo(100);
+ assertGreater(
+ "Grid should scroll vertically while editing in unbuffered mode",
+ getGridVerticalScrollPos(), originalScrollPos);
+ }
+
+ @Test
+ public void testScrollEnabledOnKeyboardOpen() {
+ int originalScrollPos = getGridVerticalScrollPos();
+
+ GridCellElement cell_5_0 = getGridElement().getCell(5, 0);
+ cell_5_0.click();
+ new Actions(getDriver()).sendKeys(Keys.ENTER).perform();
+
+ scrollGridVerticallyTo(100);
+ assertGreater(
+ "Grid should scroll vertically while editing in unbuffered mode",
+ getGridVerticalScrollPos(), originalScrollPos);
+ }
+
+ @Test
+ public void testEditorInDisabledGrid() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ selectMenuPath("Component", "State", "Enabled");
+ assertEditorOpen();
+
+ assertTrue("Editor text field should be disabled",
+ null != getEditorWidgets().get(2).getAttribute("disabled"));
+
+ selectMenuPath("Component", "State", "Enabled");
+ assertEditorOpen();
+
+ assertFalse("Editor text field should not be disabled",
+ null != getEditorWidgets().get(2).getAttribute("disabled"));
+ }
+
+ @Test
+ public void testMouseOpeningClosing() {
+
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorOpen();
+
+ selectMenuPath(CANCEL_EDIT);
+ selectMenuPath(TOGGLE_EDIT_ENABLED);
+
+ getGridElement().getCell(4, 0).doubleClick();
+ assertEditorClosed();
+ }
+
+ @Test
+ public void testProgrammaticOpeningWhenOpen() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+ assertEquals("Editor should edit row 5", "(5, 0)", getEditorWidgets()
+ .get(0).getAttribute("value"));
+
+ selectMenuPath(EDIT_ITEM_100);
+ assertEditorOpen();
+ assertEquals("Editor should edit row 100", "(100, 0)",
+ getEditorWidgets().get(0).getAttribute("value"));
+ }
+
+ @Test
+ public void testExternalValueChangePassesToEditor() {
+ selectMenuPath(EDIT_ITEM_5);
+ assertEditorOpen();
+
+ selectMenuPath("Component", "State", "ReactiveValueChanger");
+
+ getEditorWidgets().get(0).click();
+ getEditorWidgets().get(0).sendKeys("changing value");
+
+ // Focus another field to cause the value to be sent to the server
+ getEditorWidgets().get(2).click();
+
+ assertEquals("Value of Column 2 in the editor was not changed",
+ "Modified", getEditorWidgets().get(2).getAttribute("value"));
+ }
+
+ @Test
+ public void testEditorClosedOnUserSort() {
+ selectMenuPath(EDIT_ITEM_5);
+
+ getGridElement().getHeaderCell(0, 0).click();
+
+ assertEditorClosed();
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java
new file mode 100644
index 0000000000..ca9d78409c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.grid.basicfeatures.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.MenuBarElement;
+import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
+
+/**
+ * Test for server-side Grid focus features.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class GridFocusTest extends GridBasicFeaturesTest {
+
+ @Before
+ public void setUp() {
+ openTestURL();
+ }
+
+ @Test
+ public void testFocusListener() {
+ selectMenuPath("Component", "Listeners", "Focus listener");
+
+ getGridElement().click();
+
+ assertTrue("Focus listener should be invoked",
+ getLogRow(0).contains("FocusEvent"));
+ }
+
+ @Test
+ public void testBlurListener() {
+ selectMenuPath("Component", "Listeners", "Blur listener");
+
+ getGridElement().click();
+ $(MenuBarElement.class).first().click();
+
+ assertTrue("Blur listener should be invoked",
+ getLogRow(0).contains("BlurEvent"));
+ }
+
+ @Test
+ public void testProgrammaticFocus() {
+ selectMenuPath("Component", "State", "Set focus");
+
+ assertTrue("Grid cell (0, 0) should be focused", getGridElement()
+ .getCell(0, 0).isFocused());
+ }
+
+ @Test
+ public void testTabIndex() {
+ assertEquals(getGridElement().getAttribute("tabindex"), "0");
+
+ selectMenuPath("Component", "State", "Tab index", "-1");
+ assertEquals(getGridElement().getAttribute("tabindex"), "-1");
+
+ selectMenuPath("Component", "State", "Tab index", "10");
+ assertEquals(getGridElement().getAttribute("tabindex"), "10");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java
index 9953bbcae0..8bf8639d76 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java
@@ -20,8 +20,10 @@ import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.GridElement;
@@ -335,6 +337,62 @@ public class GridSelectionTest extends GridBasicFeaturesTest {
getRow(5).isSelected());
}
+ @Test
+ public void testSelectionCheckBoxesHaveStyleNames() {
+ openTestURL();
+
+ setSelectionModelMulti();
+
+ assertTrue(
+ "Selection column CheckBox should have the proper style name set",
+ getGridElement().getCell(0, 0).findElement(By.tagName("span"))
+ .getAttribute("class")
+ .contains("v-grid-selection-checkbox"));
+
+ GridCellElement header = getGridElement().getHeaderCell(0, 0);
+ assertTrue("Select all CheckBox should have the proper style name set",
+ header.findElement(By.tagName("span")).getAttribute("class")
+ .contains("v-grid-select-all-checkbox"));
+ }
+
+ @Test
+ public void testServerSideSelectTogglesSelectAllCheckBox() {
+ openTestURL();
+
+ setSelectionModelMulti();
+ GridCellElement header = getGridElement().getHeaderCell(0, 0);
+
+ WebElement selectAll = header.findElement(By.tagName("input"));
+
+ selectMenuPath("Component", "State", "Select all");
+ waitUntilCheckBoxValue(selectAll, true);
+ assertTrue("Select all CheckBox wasn't selected as expected",
+ selectAll.isSelected());
+
+ selectMenuPath("Component", "State", "Select none");
+ waitUntilCheckBoxValue(selectAll, false);
+ assertFalse("Select all CheckBox was selected unexpectedly",
+ selectAll.isSelected());
+
+ selectMenuPath("Component", "State", "Select all");
+ waitUntilCheckBoxValue(selectAll, true);
+ getGridElement().getCell(5, 0).click();
+ waitUntilCheckBoxValue(selectAll, false);
+ assertFalse("Select all CheckBox was selected unexpectedly",
+ selectAll.isSelected());
+ }
+
+ private void waitUntilCheckBoxValue(final WebElement checkBoxElememnt,
+ final boolean expectedValue) {
+ waitUntil(new ExpectedCondition<Boolean>() {
+ @Override
+ public Boolean apply(WebDriver input) {
+ return expectedValue ? checkBoxElememnt.isSelected()
+ : !checkBoxElememnt.isSelected();
+ }
+ }, 5);
+ }
+
private void setSelectionModelMulti() {
selectMenuPath("Component", "State", "Selection mode", "multi");
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java
index 0e5dd32989..238b470feb 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java
@@ -45,15 +45,15 @@ public class GridSidebarThemeTest extends GridBasicFeaturesTest {
private void runTestSequence(String theme) throws IOException {
openTestURL("theme=" + theme);
- compareScreen(theme + "_SidebarClosed");
+ compareScreen(theme + "-SidebarClosed");
getSidebarOpenButton().click();
- compareScreen(theme + "_SidebarOpen");
+ compareScreen(theme + "-SidebarOpen");
new Actions(getDriver()).moveToElement(getColumnHidingToggle(2), 5, 5)
.perform();
- compareScreen(theme + "_OnMouseOverNotHiddenToggle");
+ compareScreen(theme + "-OnMouseOverNotHiddenToggle");
getColumnHidingToggle(2).click();
getColumnHidingToggle(3).click();
@@ -63,17 +63,17 @@ public class GridSidebarThemeTest extends GridBasicFeaturesTest {
.perform();
;
- compareScreen(theme + "_TogglesTriggered");
+ compareScreen(theme + "-TogglesTriggered");
new Actions(getDriver()).moveToElement(getColumnHidingToggle(2))
.perform();
;
- compareScreen(theme + "_OnMouseOverHiddenToggle");
+ compareScreen(theme + "-OnMouseOverHiddenToggle");
getSidebarOpenButton().click();
- compareScreen(theme + "_SidebarClosed2");
+ compareScreen(theme + "-SidebarClosed2");
}
@Override
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java
index 5d72d481c7..f44f39689c 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java
@@ -274,7 +274,7 @@ public class GridStructureTest extends GridBasicFeaturesTest {
@Test
public void testBareItemSetChangeRemovingAllRows() throws Exception {
openTestURL();
- selectMenuPath("Component", "Filter", "Add impassable filter");
+ selectMenuPath("Component", "Filter", "Impassable filter");
assertFalse("A notification shouldn't have been displayed",
$(NotificationElement.class).exists());
assertTrue("No body cells should've been found", getGridElement()
diff --git a/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java b/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java
index 3005365c47..6155820990 100644
--- a/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java
+++ b/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java
@@ -15,13 +15,15 @@
*/
package com.vaadin.tests.components.popupview;
-import com.vaadin.tests.tb3.MultiBrowserTest;
import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
+import com.vaadin.testbench.parallel.BrowserUtil;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
/**
* Check availability of shortcut action listener in the popup view.
*
@@ -29,6 +31,14 @@ import org.openqa.selenium.WebElement;
*/
public class PopupViewShortcutActionHandlerTest extends MultiBrowserTest {
+ @Override
+ protected boolean requireWindowFocusForIE() {
+ if (BrowserUtil.isIE8(getDesiredCapabilities())) {
+ return false;
+ }
+ return true;
+ }
+
@Test
public void testShortcutHandling() {
openTestURL();
diff --git a/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java
new file mode 100644
index 0000000000..0dc371e57c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java
@@ -0,0 +1,58 @@
+package com.vaadin.tests.components.splitpanel;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.event.FieldEvents.TextChangeEvent;
+import com.vaadin.event.FieldEvents.TextChangeListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.Window;
+
+@Theme("reindeer")
+public class GridLayoutWithCheckbox extends UI {
+
+ @Override
+ protected void init(VaadinRequest request) {
+ GridLayout grid = new GridLayout(2, 3);
+ grid.setWidth(500, Unit.PIXELS);
+
+ Label l = new Label("Textfield 1:");
+ grid.addComponent(l, 0, 0);
+ TextField textfield = new TextField();
+ textfield.addTextChangeListener(new TextChangeListener() {
+
+ @Override
+ public void textChange(TextChangeEvent event) {
+
+ }
+ });
+ textfield.setTextChangeEventMode(TextChangeEventMode.EAGER);
+ grid.addComponent(textfield, 1, 0);
+
+ l = new Label("CheckBox:");
+ grid.addComponent(l, 0, 1);
+ CheckBox checkBox = new CheckBox();
+ grid.addComponent(checkBox, 1, 2);
+ checkBox.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ }
+ });
+ Window window = new Window();
+ window.setWidth(300.0f, Unit.PIXELS);
+ window.setContent(grid);
+ window.setResizable(false);
+ window.setWidth(550, Unit.PIXELS);
+
+ // grid.setColumnExpandRatio(1, 1);
+ addWindow(window);
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java
new file mode 100644
index 0000000000..fee46c155a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.splitpanel;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Dimension;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.elements.CheckBoxElement;
+import com.vaadin.testbench.elements.TextFieldElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class GridLayoutWithCheckboxTest extends MultiBrowserTest {
+
+ private TextFieldElement tf;
+ private WebElement tfSlot;
+ private CheckBoxElement cb;
+ private WebElement cbSlot;
+ private Dimension tfSize;
+ private Dimension tfSlotSize;
+ private Dimension cbSize;
+ private Dimension cbSlotSize;
+
+ @Test
+ public void layoutShouldStayTheSame() {
+ openTestURL();
+ tf = $(TextFieldElement.class).first();
+ tfSlot = tf.findElement(By.xpath(".."));
+ cb = $(CheckBoxElement.class).first();
+ cbSlot = cb.findElement(By.xpath(".."));
+
+ // Doing anything with the textfield or checkbox should not affect
+ // layout
+
+ tf.setValue("a");
+ assertSizes();
+ cb.click();
+ assertSizes();
+ tf.setValue("b");
+ assertSizes();
+ cb.click();
+ assertSizes();
+
+ }
+
+ private void assertSizes() {
+ if (tfSize == null) {
+ tfSize = tf.getSize();
+ tfSlotSize = tfSlot.getSize();
+ cbSize = cb.getSize();
+ cbSlotSize = cbSlot.getSize();
+ } else {
+ Assert.assertEquals(tfSize, tf.getSize());
+ Assert.assertEquals(tfSlotSize, tfSlot.getSize());
+ Assert.assertEquals(cbSize, cb.getSize());
+ Assert.assertEquals(cbSlotSize, cbSlot.getSize());
+ }
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java
index 08b65e2ef5..8d1a9fc7df 100644
--- a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java
+++ b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java
@@ -2,21 +2,22 @@ package com.vaadin.tests.components.table;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
-import com.vaadin.tests.components.TestBase;
-import com.vaadin.ui.Alignment;
+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.HorizontalLayout;
import com.vaadin.ui.Table;
-import com.vaadin.ui.TextField;
+import com.vaadin.ui.Table.ColumnCollapseEvent;
+import com.vaadin.ui.Table.ColumnCollapseListener;
-public class ColumnCollapsingAndColumnExpansion extends TestBase {
+public class ColumnCollapsingAndColumnExpansion extends AbstractTestUIWithLog {
private Table table;
@Override
- public void setup() {
+ protected void setup(VaadinRequest request) {
table = new Table();
@@ -50,41 +51,44 @@ public class ColumnCollapsingAndColumnExpansion extends TestBase {
"cell " + 2 + "-" + y, "cell " + 3 + "-" + y, },
new Object());
}
-
- addComponent(table);
-
- HorizontalLayout hl = new HorizontalLayout();
- final TextField tf = new TextField("Column name (ColX)");
- Button hide = new Button("Collapse", new ClickListener() {
+ table.addColumnCollapseListener(new ColumnCollapseListener() {
@Override
- public void buttonClick(ClickEvent event) {
- table.setColumnCollapsed(tf.getValue(), true);
- }
-
- });
+ public void columnCollapseStateChange(ColumnCollapseEvent event) {
+ log("Collapse state for " + event.getPropertyId()
+ + " changed to "
+ + table.isColumnCollapsed(event.getPropertyId()));
- Button show = new Button("Show", new ClickListener() {
-
- @Override
- public void buttonClick(ClickEvent event) {
- table.setColumnCollapsed(tf.getValue(), false);
}
-
});
+ addComponent(table);
- hl.addComponent(tf);
- hl.addComponent(hide);
- hl.addComponent(show);
- hl.setComponentAlignment(tf, Alignment.BOTTOM_LEFT);
- hl.setComponentAlignment(hide, Alignment.BOTTOM_LEFT);
- hl.setComponentAlignment(show, Alignment.BOTTOM_LEFT);
- addComponent(hl);
+ for (int i = 1; i <= 3; i++) {
+ HorizontalLayout hl = new HorizontalLayout();
+ final String id = "Col" + i;
+ Button hide = new Button("Collapse " + id, new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ table.setColumnCollapsed(id, true);
+ }
+ });
+
+ Button show = new Button("Show " + id, new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ table.setColumnCollapsed(id, false);
+ }
+ });
+
+ hl.addComponent(hide);
+ hl.addComponent(show);
+ addComponent(hl);
+ }
}
@Override
- protected String getDescription() {
+ protected String getTestDescription() {
return "After hiding column 2 the remaining columns (1 and 3) should use all available space in the table";
}
diff --git a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java
new file mode 100644
index 0000000000..739851de2f
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.parallel.BrowserUtil;
+import com.vaadin.tests.components.table.CustomTableElement.ContextMenuElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class ColumnCollapsingAndColumnExpansionTest extends MultiBrowserTest {
+
+ @Test
+ public void expandCorrectlyAfterCollapse() throws IOException {
+ openTestURL();
+
+ CustomTableElement table = $(CustomTableElement.class).first();
+
+ // Hide col2 through UI
+ table.openCollapseMenu().getItem(1).click();
+ compareScreen(table, "col1-col3");
+
+ // Hide col1 using button
+ ButtonElement hide1 = $(ButtonElement.class).caption("Collapse Col1")
+ .first();
+ hide1.click();
+ compareScreen(table, "col3");
+
+ // Show column 2 using context menu (first action)
+ if (BrowserUtil.isIE8(getDesiredCapabilities())) {
+ // IE8 can context click but the popup is off screen so it can't be
+ // interacted with...
+ ButtonElement show2 = $(ButtonElement.class).caption("Show Col2")
+ .first();
+ show2.click();
+ } else {
+ contextClick(table.getCell(0, 0));
+ ContextMenuElement contextMenu = table.getContextMenu();
+ WebElement i = contextMenu.getItem(0);
+ i.click();
+ }
+ compareScreen(table, "col2-col3");
+
+ // Show column 1 again
+ ButtonElement show1 = $(ButtonElement.class).caption("Show Col1")
+ .first();
+ show1.click();
+
+ compareScreen(table, "col1-col2-col3");
+ }
+
+ private void contextClick(TestBenchElement e) {
+ if (e.isPhantomJS()) {
+ JavascriptExecutor js = e.getCommandExecutor();
+ String scr = "var element=arguments[0];"
+ + "var ev = document.createEvent('HTMLEvents');"
+ + "ev.initEvent('contextmenu', true, false);"
+ + "element.dispatchEvent(ev);";
+ js.executeScript(scr, e);
+ } else {
+ e.contextClick();
+ }
+
+ }
+
+ @Test
+ public void collapseEvents() {
+ openTestURL();
+ CustomTableElement table = $(CustomTableElement.class).first();
+
+ // Through menu
+ table.openCollapseMenu().getItem(0).click();
+ Assert.assertEquals("1. Collapse state for Col1 changed to true",
+ getLogRow(0));
+
+ // Through button
+ $(ButtonElement.class).caption("Collapse Col2").first().click();
+ Assert.assertEquals("2. Collapse state for Col2 changed to true",
+ getLogRow(0));
+
+ // Show through menu
+ table.openCollapseMenu().getItem(1).click();
+ Assert.assertEquals("3. Collapse state for Col1 changed to false",
+ getLogRow(0));
+
+ // Show through button
+ $(ButtonElement.class).caption("Show Col2").first().click();
+ Assert.assertEquals("4. Collapse state for Col2 changed to false",
+ getLogRow(0));
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/CustomTableElement.java b/uitest/src/com/vaadin/tests/components/table/CustomTableElement.java
new file mode 100644
index 0000000000..f1df98fb38
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/CustomTableElement.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.tests.components.table;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.elements.TableElement;
+import com.vaadin.testbench.elementsbase.AbstractElement;
+import com.vaadin.testbench.elementsbase.ServerClass;
+
+@ServerClass("com.vaadin.ui.Table")
+public class CustomTableElement extends TableElement {
+
+ public CollapseMenu openCollapseMenu() {
+ getCollapseMenuToggle().click();
+ WebElement cm = getDriver().findElement(
+ By.xpath("//*[@id='PID_VAADIN_CM']"));
+ return wrapElement(cm, getCommandExecutor()).wrap(CollapseMenu.class);
+ }
+
+ public static class CollapseMenu extends ContextMenuElement {
+ }
+
+ public WebElement getCollapseMenuToggle() {
+ return findElement(By.className("v-table-column-selector"));
+ }
+
+ public static class ContextMenuElement extends AbstractElement {
+
+ public WebElement getItem(int index) {
+ return findElement(By.xpath(".//table//tr[" + (index + 1)
+ + "]//td/*"));
+ }
+
+ }
+
+ public ContextMenuElement getContextMenu() {
+ WebElement cm = getDriver().findElement(By.className("v-contextmenu"));
+ return wrapElement(cm, getCommandExecutor()).wrap(
+ ContextMenuElement.class);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java
new file mode 100644
index 0000000000..8f0a8803f3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java
@@ -0,0 +1,50 @@
+/*
+ * 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.annotations.Theme;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.tests.fieldgroup.ComplexPerson;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Table;
+
+@Theme("valo")
+public class TableColumnWidthsAndSorting extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final Table t = new Table();
+ t.setContainerDataSource(ComplexPerson.createContainer(100));
+ t.setVisibleColumns("firstName", "lastName", "age", "gender", "salary");
+ t.setColumnWidth("firstName", 200);
+ t.setColumnWidth("lastName", 200);
+ t.setSelectable(true);
+ addComponent(t);
+
+ Button b = new Button("Sort according to gender", new ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ t.sort(new Object[] { "gender" }, new boolean[] { true });
+ }
+ });
+
+ addComponent(b);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java
new file mode 100644
index 0000000000..9c49b3d0b6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.vaadin.testbench.elements.TableElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class TableColumnWidthsAndSortingTest extends MultiBrowserTest {
+
+ @Test
+ public void testHeaderHeight() {
+ openTestURL();
+ TableElement t = $(TableElement.class).first();
+
+ assertHeaderCellHeight(t);
+
+ // Sort according to age
+ t.getHeaderCell(2).click();
+ assertHeaderCellHeight(t);
+
+ // Sort again according to age
+ t.getHeaderCell(2).click();
+ assertHeaderCellHeight(t);
+
+ }
+
+ private void assertHeaderCellHeight(TableElement t) {
+ // Assert all headers are correct height (37px according to default
+ // Valo)
+ for (int i = 0; i < 5; i++) {
+ Assert.assertEquals("Height of header cell " + i + " is wrong", 37,
+ t.getHeaderCell(0).getSize().getHeight());
+ }
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java
new file mode 100644
index 0000000000..b2313020a3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.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.tabsheet;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalSplitPanel;
+import com.vaadin.ui.themes.ValoTheme;
+
+@Theme("valo")
+public class TabSheetInSplitPanel extends UI {
+
+ @Override
+ protected void init(VaadinRequest request) {
+ VerticalSplitPanel verticalSplitter = new VerticalSplitPanel();
+ setContent(verticalSplitter);
+ verticalSplitter.setSizeFull();
+ TabSheet t = new TabSheet();
+ t.setHeight("100%");
+ t.addTab(new Label("Hello in tab"), "Hello tab");
+ t.setStyleName(ValoTheme.TABSHEET_FRAMED);
+ verticalSplitter.addComponent(t);
+ verticalSplitter.addComponent(new Label("Hello"));
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java
new file mode 100644
index 0000000000..8070133bde
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.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.tabsheet;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.elements.TabSheetElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class TabSheetInSplitPanelTest extends MultiBrowserTest {
+
+ @Test
+ public void ensureNoScrollbars() {
+ openTestURL();
+ TabSheetElement ts = $(TabSheetElement.class).first();
+ List<WebElement> scrollables = ts.findElements(By
+ .xpath("//*[contains(@class,'v-scrollable')]"));
+ for (WebElement scrollable : scrollables) {
+ assertNoHorizontalScrollbar(scrollable,
+ "Element should not have a horizontal scrollbar");
+ assertNoVerticalScrollbar(scrollable,
+ "Element should not have a vertical scrollbar");
+ }
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java
new file mode 100644
index 0000000000..07cf7f8c2e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java
@@ -0,0 +1,51 @@
+/*
+ * 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.treetable;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.TreeTable;
+
+public class TreeTableScrollOnExpand extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ TreeTable t = new TreeTable();
+ t.setSelectable(true);
+ t.setImmediate(true);
+ t.setSizeFull();
+ t.addContainerProperty("Name", String.class, "null");
+ for (int i = 1; i <= 100; i++) {
+ String parentID = "Item " + i;
+ Object parent = t.addItem(new Object[] { parentID }, parentID);
+ String childID = "Item " + (100 + i);
+ Object child = t.addItem(new Object[] { childID }, childID);
+ t.getContainerDataSource().setParent(childID, parentID);
+ }
+ addComponent(t);
+ }
+
+ @Override
+ public Integer getTicketNumber() {
+ return 18247;
+ }
+
+ @Override
+ public String getTestDescription() {
+ return "After selecting an item and scrolling it out of view, TreeTable should not scroll to the "
+ + "selected item when expanding an item.";
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java
new file mode 100644
index 0000000000..a17559cc81
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.treetable;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.elements.TreeTableElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class TreeTableScrollOnExpandTest extends MultiBrowserTest {
+
+ @Test
+ public void testScrollOnExpand() throws InterruptedException, IOException {
+ openTestURL();
+ TreeTableElement tt = $(TreeTableElement.class).first();
+ tt.getRow(0).click();
+ tt.scroll(300);
+ sleep(1000);
+ tt.getRow(20).toggleExpanded();
+ // Need to wait a bit to avoid accepting the case where the TreeTable is
+ // in the desired state only for a short while.
+ sleep(1000);
+ WebElement focusedRow = getDriver().findElement(
+ By.className("v-table-focus"));
+ assertEquals("Item 21", focusedRow.getText());
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/window/GridInWindow.java b/uitest/src/com/vaadin/tests/components/window/GridInWindow.java
new file mode 100644
index 0000000000..918a991cc1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/GridInWindow.java
@@ -0,0 +1,49 @@
+/*
+ * 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.window;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Window;
+
+public class GridInWindow extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final Grid grid = new Grid();
+
+ grid.addColumn("Hidable column").setHidable(true);
+ grid.addRow("Close and reopen and it vanishes");
+
+ Button popupButton = new Button("Open PopUp",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(Button.ClickEvent event) {
+ Window subWindow = new Window("Sub-window");
+ subWindow.setContent(grid);
+ subWindow.setWidth(600, Unit.PIXELS);
+ subWindow.setWidth(400, Unit.PIXELS);
+ getUI().addWindow(subWindow);
+ }
+ });
+
+ addComponent(popupButton);
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java b/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java
new file mode 100644
index 0000000000..301a7c60e4
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.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.window;
+
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+import com.vaadin.tests.tb3.newelements.WindowElement;
+
+public class GridInWindowTest extends SingleBrowserTest {
+
+ @Test
+ public void ensureAttachInHierachyChange() {
+ openTestURL("debug");
+ $(ButtonElement.class).first().click();
+ assertNoErrorNotifications();
+ $(WindowElement.class).first().close();
+ assertNoErrorNotifications();
+ $(ButtonElement.class).first().click();
+ assertNoErrorNotifications();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java
new file mode 100644
index 0000000000..1c82a3de02
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.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.window;
+
+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.TextArea;
+import com.vaadin.ui.Window;
+
+public class OpenModalWindowAndFocusField extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Button button = new Button("Open modal and focus textarea");
+ button.setId("openFocus");
+ button.addClickListener(new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ open(true);
+ }
+ });
+ addComponent(button);
+
+ button = new Button("Only open modal");
+ button.setId("open");
+ button.addClickListener(new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ open(false);
+ }
+
+ });
+ addComponent(button);
+
+ }
+
+ private void open(boolean focus) {
+ Window wind = new Window();
+ wind.setModal(true);
+ TextArea ta = new TextArea();
+ wind.setContent(ta);
+ addWindow(wind);
+ if (focus) {
+ ta.focus();
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java
new file mode 100644
index 0000000000..5dba1c3285
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.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.window;
+
+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.TextAreaElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class OpenModalWindowAndFocusFieldTest extends MultiBrowserTest {
+
+ @Test
+ public void openModalAndFocusField() {
+ openTestURL();
+ $(ButtonElement.class).id("openFocus").click();
+ TextAreaElement textArea = $(TextAreaElement.class).first();
+
+ assertElementsEquals(textArea, getActiveElement());
+ }
+
+ @Test
+ public void openModal() {
+ openTestURL();
+ $(ButtonElement.class).id("open").click();
+ // WindowElement window = $(WindowElement.class).first();
+ WebElement windowFocusElement = findElement(By
+ .xpath("//div[@class='v-window-contents']/div[@class='v-scrollable']"));
+
+ assertElementsEquals(windowFocusElement, getActiveElement());
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/window/WindowCloseShortcuts.java b/uitest/src/com/vaadin/tests/components/window/WindowCloseShortcuts.java
new file mode 100644
index 0000000000..d9c22a26ee
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/WindowCloseShortcuts.java
@@ -0,0 +1,199 @@
+/*
+ * 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.window;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Attribute;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.event.ShortcutAction.KeyCode;
+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.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.declarative.Design;
+import com.vaadin.ui.declarative.DesignContext;
+
+@Theme("valo")
+@SuppressWarnings("serial")
+public class WindowCloseShortcuts extends AbstractTestUI {
+
+ private Window window;
+ private Label designLabel;
+ private VerticalLayout buttonLayout;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ getLayout().setSpacing(true);
+
+ window = new Window("Test window");
+ window.setVisible(true);
+ window.setModal(true);
+ window.setContent(new RichTextArea());
+
+ Panel buttonPanel = new Panel();
+ buttonLayout = new VerticalLayout();
+ buttonLayout.setSizeFull();
+ buttonPanel.setCaption("Demo controls");
+
+ addButton(new Button("Open window", new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ UI.getCurrent().addWindow(window);
+ window.center();
+ updateDesign();
+ }
+ }));
+
+ addButton(new Button("Add ENTER close shortcut", new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ window.addCloseShortcut(KeyCode.ENTER);
+ updateDesign();
+ }
+ }));
+
+ addButton(new Button("Add TAB close shortcut", new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ window.addCloseShortcut(KeyCode.TAB);
+ updateDesign();
+ }
+ }));
+
+ addButton(new Button("Remove ESC close shortcut", new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ window.removeCloseShortcut(KeyCode.ESCAPE);
+ updateDesign();
+ }
+ }));
+
+ addButton(new Button("Clear all close shortcuts", new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ window.removeAllCloseShortcuts();
+ updateDesign();
+ }
+ }));
+
+ addButton(new Button("Reset to default state", new ClickListener() {
+ @Override
+ @SuppressWarnings("deprecation")
+ public void buttonClick(ClickEvent event) {
+ window.removeCloseShortcut();
+ updateDesign();
+ }
+ }));
+
+ buttonPanel.setContent(buttonLayout);
+ buttonPanel.setSizeUndefined();
+ addComponent(buttonPanel);
+ buttonPanel.setWidth("400px");
+
+ Panel designPanel = new Panel();
+ designPanel.setCaption("Window design");
+ designLabel = new Label("");
+ VerticalLayout designLayout = new VerticalLayout();
+ designLayout.addComponent(designLabel);
+ designPanel.setContent(designLayout);
+ addComponent(designPanel);
+
+ updateDesign();
+ }
+
+ private void addButton(Button b) {
+ b.setWidth("100%");
+ buttonLayout.addComponent(b);
+ }
+
+ //
+ // The following code is adapted from DeclarativeTestBaseBase.java
+ // (that's not a typo)
+ //
+
+ private void updateDesign() {
+ String design = "";
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ DesignContext dc = new DesignContext();
+ dc.setRootComponent(window);
+ Design.write(dc, outputStream);
+ design = outputStream.toString("UTF-8");
+ } catch (Exception e) {
+ return;
+ }
+ Element producedElem = Jsoup.parse(design).body().child(0);
+ design = elementToHtml(producedElem);
+ designLabel.setCaption(design);
+ }
+
+ //
+ // The following code is copied directly from DeclarativeTestBaseBase.java
+ // (that's not a typo, either)
+ //
+
+ private String elementToHtml(Element producedElem) {
+ StringBuilder stringBuilder = new StringBuilder();
+ elementToHtml(producedElem, stringBuilder);
+ return stringBuilder.toString();
+ }
+
+ private String elementToHtml(Element producedElem, StringBuilder sb) {
+ ArrayList<String> names = new ArrayList<String>();
+ for (Attribute a : producedElem.attributes().asList()) {
+ names.add(a.getKey());
+ }
+ Collections.sort(names);
+
+ sb.append("<" + producedElem.tagName() + "");
+ for (String attrName : names) {
+ sb.append(" ").append(attrName).append("=").append("\'")
+ .append(producedElem.attr(attrName)).append("\'");
+ }
+ sb.append(">");
+ for (Node child : producedElem.childNodes()) {
+ if (child instanceof Element) {
+ elementToHtml((Element) child, sb);
+ } else if (child instanceof TextNode) {
+ String text = ((TextNode) child).text();
+ sb.append(text.trim());
+ }
+ }
+ sb.append("</").append(producedElem.tagName()).append(">");
+ return sb.toString();
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 17383;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java
new file mode 100644
index 0000000000..0ac2e87510
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java
@@ -0,0 +1,33 @@
+/*
+ * 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.debug;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.ui.Label;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class PreserveCustomDebugSectionOpen extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ addComponent(new Label(
+ "UI for testing that a custom debug window section remains open after refreshging."));
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java
new file mode 100644
index 0000000000..01b73ded92
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.debug;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class PreserveCustomDebugSectionOpenTest extends SingleBrowserTest {
+ @Test
+ public void testPreserveSection() {
+ setDebug(true);
+ openTestURL();
+
+ findElement(
+ By.cssSelector(".v-debugwindow-tabs button[title=\"Dummy debug window section\"]"))
+ .click();
+
+ WebElement content = findElement(By
+ .cssSelector(".v-debugwindow-content"));
+
+ // Sanity check
+ Assert.assertEquals("Dummy debug window section", content.getText());
+
+ // Open page again, should still have the same section open
+ openTestURL();
+
+ content = findElement(By.cssSelector(".v-debugwindow-content"));
+ Assert.assertEquals("Dummy debug window section", content.getText());
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/debug/ProfilerZeroOverhead.java b/uitest/src/com/vaadin/tests/debug/ProfilerZeroOverhead.java
new file mode 100644
index 0000000000..7daf38a0e5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/debug/ProfilerZeroOverhead.java
@@ -0,0 +1,37 @@
+/*
+ * 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.debug;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.tests.widgetset.client.ProfilerCompilationCanary;
+import com.vaadin.tests.widgetset.server.TestWidgetComponent;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class ProfilerZeroOverhead extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ addComponent(new TestWidgetComponent(ProfilerCompilationCanary.class));
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Test UI for verifying that Profiler.isEnabled() causes no side effects in generated javascript";
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/debug/ProfilerZeroOverheadTest.java b/uitest/src/com/vaadin/tests/debug/ProfilerZeroOverheadTest.java
new file mode 100644
index 0000000000..659823e49a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/debug/ProfilerZeroOverheadTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.debug;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class ProfilerZeroOverheadTest extends SingleBrowserTest {
+ @Test
+ public void testZeroOverhead() {
+ openTestURL();
+
+ /*
+ * This will get the compiled JS for the
+ * ProfilerCompilationCanary.canaryWithProfiler method. Expected to be
+ * something like "function canaryWithProfiler(){\n}" with a PRETTY
+ * non-draft widgetset.
+ */
+ String canaryMethodString = findElement(By.className("gwt-Label"))
+ .getText();
+
+ // Only look at the method body to avoid false negatives if e.g.
+ // obfuscation changes
+ int bodyStart = canaryMethodString.indexOf('{');
+ int bodyEnd = canaryMethodString.lastIndexOf('}');
+
+ String methodBody = canaryMethodString
+ .substring(bodyStart + 1, bodyEnd);
+
+ // Method body shouldn't contain anything else than whitespace
+ if (!methodBody.replaceAll("\\s", "").isEmpty()) {
+ Assert.fail("Canary method is not empty: " + canaryMethodString);
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java
index f611325719..2562412480 100644
--- a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java
+++ b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java
@@ -20,18 +20,25 @@ import org.junit.Assert;
import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.CheckBoxElement;
-import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.testbench.elements.TableElement;
import com.vaadin.testbench.elements.TableRowElement;
import com.vaadin.testbench.elements.TextAreaElement;
import com.vaadin.testbench.elements.TextFieldElement;
import com.vaadin.tests.data.bean.Sex;
import com.vaadin.tests.tb3.MultiBrowserTest;
+import com.vaadin.tests.tb3.newelements.FixedNotificationElement;
public abstract class BasicPersonFormTest extends MultiBrowserTest {
private static final String BEAN_VALUES = "Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]";
- private int logCounter = 0;
+ private int logCounter;
+
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+
+ logCounter = 0;
+ }
@Override
protected Class<?> getUIClass() {
@@ -75,7 +82,7 @@ public abstract class BasicPersonFormTest extends MultiBrowserTest {
}
protected void closeNotification() {
- $(NotificationElement.class).first().close();
+ $(FixedNotificationElement.class).first().close();
}
protected CheckBoxElement getPostCommitFailsCheckBox() {
@@ -169,5 +176,4 @@ public abstract class BasicPersonFormTest extends MultiBrowserTest {
assertSelectedSex(Sex.MALE);
assertDeceasedValue("NAAAAAH");
}
-
}
diff --git a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java
index 37f8e21c50..800a056041 100644
--- a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java
+++ b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java
@@ -110,10 +110,16 @@ public class JSR286Portlet extends UI {
}
private void possiblyChangedModeOrState() {
- VaadinPortletRequest request = (VaadinPortletRequest) VaadinPortletService
- .getCurrentRequest();
-
- userAgent.setValue(getPage().getWebBrowser().getBrowserApplication());
+ VaadinPortletRequest request = VaadinPortletService.getCurrentRequest();
+
+ String censoredUserAgent = getPage().getWebBrowser()
+ .getBrowserApplication();
+ if (censoredUserAgent != null && censoredUserAgent.contains("Chrome/")) {
+ // Censor version info as it tends to change
+ censoredUserAgent = censoredUserAgent.replaceAll("Chrome/[^ ]* ",
+ "Chrome/xyz ");
+ }
+ userAgent.setValue(censoredUserAgent);
screenWidth.setValue(String.valueOf(getPage().getBrowserWindowWidth()));
screenHeight.setValue(String
.valueOf(getPage().getBrowserWindowHeight()));
diff --git a/uitest/src/com/vaadin/tests/push/BasicPushLongPollingTest.java b/uitest/src/com/vaadin/tests/push/BasicPushLongPollingTest.java
index b404747c80..a060d5a57a 100644
--- a/uitest/src/com/vaadin/tests/push/BasicPushLongPollingTest.java
+++ b/uitest/src/com/vaadin/tests/push/BasicPushLongPollingTest.java
@@ -15,5 +15,19 @@
*/
package com.vaadin.tests.push;
+import org.junit.Test;
+
public class BasicPushLongPollingTest extends BasicPushTest {
+
+ @Test
+ public void pushAfterServerTimeout() throws InterruptedException {
+ getDriver().get(
+ getTestUrl().replace("/run/", "/run-push-timeout/")
+ + "?debug=push");
+ sleep(11000); // Wait for server timeout (10s)
+
+ getServerCounterStartButton().click();
+ waitUntilServerCounterChanges();
+ }
+
}
diff --git a/uitest/src/com/vaadin/tests/push/BasicPushTest.java b/uitest/src/com/vaadin/tests/push/BasicPushTest.java
index 0e86902b50..157e3f74ae 100644
--- a/uitest/src/com/vaadin/tests/push/BasicPushTest.java
+++ b/uitest/src/com/vaadin/tests/push/BasicPushTest.java
@@ -58,11 +58,11 @@ public abstract class BasicPushTest extends MultiBrowserTest {
return Integer.parseInt(clientCounterElem.getText());
}
- private WebElement getIncrementButton() {
+ protected WebElement getIncrementButton() {
return getIncrementButton(this);
}
- private WebElement getServerCounterStartButton() {
+ protected WebElement getServerCounterStartButton() {
return getServerCounterStartButton(this);
}
@@ -84,7 +84,7 @@ public abstract class BasicPushTest extends MultiBrowserTest {
return t.findElement(By.id(BasicPush.INCREMENT_BUTTON_ID));
}
- private void waitUntilClientCounterChanges(final int expectedValue) {
+ protected void waitUntilClientCounterChanges(final int expectedValue) {
waitUntil(new ExpectedCondition<Boolean>() {
@Override
@@ -94,7 +94,7 @@ public abstract class BasicPushTest extends MultiBrowserTest {
}, 10);
}
- private void waitUntilServerCounterChanges() {
+ protected void waitUntilServerCounterChanges() {
final int counter = BasicPushTest.getServerCounter(this);
waitUntil(new ExpectedCondition<Boolean>() {
diff --git a/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java
new file mode 100644
index 0000000000..190f6daa24
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java
@@ -0,0 +1,94 @@
+/*
+ * 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.push;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import com.vaadin.annotations.Push;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.communication.PushMode;
+import com.vaadin.shared.ui.ui.Transport;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+
+@Push(value = PushMode.MANUAL, transport = Transport.LONG_POLLING)
+public class ManualLongPollingPushUI extends AbstractTestUIWithLog {
+
+ ExecutorService executor = Executors.newFixedThreadPool(1);
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Button b = new Button("Manual push after 1s",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ access(new Runnable() {
+
+ @Override
+ public void run() {
+ log("Logged after 1s, followed by manual push");
+ push();
+ }
+ });
+
+ }
+ });
+ }
+ });
+ addComponent(b);
+
+ b = new Button("Double manual push after 1s",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ access(new Runnable() {
+
+ @Override
+ public void run() {
+ log("First message logged after 1s, followed by manual push");
+ push();
+ log("Second message logged after 1s, followed by manual push");
+ push();
+ }
+ });
+
+ }
+ });
+ }
+ });
+ addComponent(b);
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java
new file mode 100644
index 0000000000..096204ff75
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.push;
+
+import org.junit.Test;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class ManualLongPollingPushUITest extends SingleBrowserTest {
+
+ @Test
+ public void doubleManualPushDoesNotFreezeApplication() {
+ openTestURL();
+ $(ButtonElement.class).caption("Double manual push after 1s").first()
+ .click();
+ waitUntilLogText("2. Second message logged after 1s, followed by manual push");
+ $(ButtonElement.class).caption("Manual push after 1s").first().click();
+ waitUntilLogText("3. Logged after 1s, followed by manual push");
+ }
+
+ private void waitUntilLogText(final String expected) {
+ waitUntil(new ExpectedCondition<Boolean>() {
+ private String actual;
+
+ @Override
+ public Boolean apply(WebDriver arg0) {
+ actual = getLogRow(0);
+ return expected.equals(actual);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("log text to become '%s' (was: '%s')",
+ expected, actual);
+ }
+ });
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java b/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java
new file mode 100644
index 0000000000..e584ec73cc
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java
@@ -0,0 +1,52 @@
+/*
+ * 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.resources;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class SpecialCharsInThemeResources extends SingleBrowserTest {
+
+ @Test
+ public void loadThemeResource() {
+ loadResource("/VAADIN/themes/tests-tickets/ordinary.txt");
+ checkSource();
+ }
+
+ @Test
+ public void loadThemeResourceWithPercentage() {
+ loadResource("/VAADIN/themes/tests-tickets/percentagein%2520name.txt");
+ checkSource();
+ }
+
+ @Test
+ public void loadThemeResourceWithSpecialChars() {
+ loadResource("/VAADIN/themes/tests-tickets/folder%20with%20space/resource%20with%20special%20$chars@.txt");
+ checkSource();
+ }
+
+ private void loadResource(String path) {
+ getDriver().get(getBaseURL() + path);
+ }
+
+ private void checkSource() {
+ String source = getDriver().getPageSource();
+ Assert.assertTrue("Incorrect contents (was: " + source + ")",
+ source.contains("Just ordinary contents here"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java
index 665f1668b2..a58575890e 100644
--- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java
+++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java
@@ -51,6 +51,7 @@ import org.openqa.selenium.interactions.Keyboard;
import org.openqa.selenium.interactions.Mouse;
import org.openqa.selenium.interactions.internal.Coordinates;
import org.openqa.selenium.internal.Locatable;
+import org.openqa.selenium.internal.WrapsElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.RemoteWebDriver;
@@ -384,7 +385,7 @@ public abstract class AbstractTB3Test extends ParallelTest {
* @return
*/
public WebElement vaadinElementById(String id) {
- return driver.findElement(vaadinLocatorById(id));
+ return driver.findElement(By.id(id));
}
/**
@@ -1118,4 +1119,93 @@ public abstract class AbstractTB3Test extends ParallelTest {
return isElementPresent(By.className("v-debugwindow"));
}
+ protected void assertNoHorizontalScrollbar(WebElement element,
+ String errorMessage) {
+ // IE rounds clientWidth/clientHeight down and scrollHeight/scrollWidth
+ // up, so using clientWidth/clientHeight will fail if the element height
+ // is not an integer
+ int clientWidth = getClientWidth(element);
+ int scrollWidth = getScrollWidth(element);
+ boolean hasScrollbar = scrollWidth > clientWidth;
+
+ Assert.assertFalse(
+ "The element should not have a horizontal scrollbar (scrollWidth: "
+ + scrollWidth + ", clientWidth: " + clientWidth + "): "
+ + errorMessage, hasScrollbar);
+ }
+
+ protected void assertNoVerticalScrollbar(WebElement element,
+ String errorMessage) {
+ // IE rounds clientWidth/clientHeight down and scrollHeight/scrollWidth
+ // up, so using clientWidth/clientHeight will fail if the element height
+ // is not an integer
+ int clientHeight = getClientHeight(element);
+ int scrollHeight = getScrollHeight(element);
+ boolean hasScrollbar = scrollHeight > clientHeight;
+
+ Assert.assertFalse(
+ "The element should not have a vertical scrollbar (scrollHeight: "
+ + scrollHeight + ", clientHeight: " + clientHeight
+ + "): " + errorMessage, hasScrollbar);
+ }
+
+ protected int getScrollHeight(WebElement element) {
+ return ((Number) executeScript("return arguments[0].scrollHeight;",
+ element)).intValue();
+ }
+
+ protected int getScrollWidth(WebElement element) {
+ return ((Number) executeScript("return arguments[0].scrollWidth;",
+ element)).intValue();
+ }
+
+ /**
+ * Returns client height rounded up instead of as double because of IE9
+ * issues: https://dev.vaadin.com/ticket/18469
+ */
+ protected int getClientHeight(WebElement e) {
+ String script;
+ if (BrowserUtil.isIE8(getDesiredCapabilities())) {
+ script = "return arguments[0].clientHeight;"; //
+ } else {
+ script = "var cs = window.getComputedStyle(arguments[0]);"
+ + "return Math.ceil(parseFloat(cs.height)+parseFloat(cs.paddingTop)+parseFloat(cs.paddingBottom));";
+ }
+ return ((Number) executeScript(script, e)).intValue();
+ }
+
+ /**
+ * Returns client width rounded up instead of as double because of IE9
+ * issues: https://dev.vaadin.com/ticket/18469
+ */
+ protected int getClientWidth(WebElement e) {
+ String script;
+ if (BrowserUtil.isIE8(getDesiredCapabilities())) {
+ script = "return arguments[0].clientWidth;";
+ } else {
+ script = "var cs = window.getComputedStyle(arguments[0]);"
+ + "var h = parseFloat(cs.width)+parseFloat(cs.paddingLeft)+parseFloat(cs.paddingRight);"
+ + "return Math.ceil(h);";
+ }
+
+ return ((Number) executeScript(script, e)).intValue();
+ }
+
+ protected void assertElementsEquals(WebElement expectedElement,
+ WebElement actualElement) {
+ while (expectedElement instanceof WrapsElement) {
+ expectedElement = ((WrapsElement) expectedElement)
+ .getWrappedElement();
+ }
+ while (actualElement instanceof WrapsElement) {
+ actualElement = ((WrapsElement) actualElement).getWrappedElement();
+ }
+
+ Assert.assertEquals(expectedElement, actualElement);
+ }
+
+ protected WebElement getActiveElement() {
+ return (WebElement) executeScript("return document.activeElement;");
+
+ }
}
diff --git a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java
index 16df2ace74..23ead80fce 100644
--- a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java
+++ b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java
@@ -84,6 +84,8 @@ public abstract class MultiBrowserTest extends PrivateTB3Configuration {
@Override
public void setDesiredCapabilities(DesiredCapabilities desiredCapabilities) {
+ super.setDesiredCapabilities(desiredCapabilities);
+
if (BrowserUtil.isIE(desiredCapabilities)) {
if (requireWindowFocusForIE()) {
desiredCapabilities.setCapability(
@@ -103,8 +105,6 @@ public abstract class MultiBrowserTest extends PrivateTB3Configuration {
"name",
String.format("%s.%s", getClass().getCanonicalName(),
testName.getMethodName()));
-
- super.setDesiredCapabilities(desiredCapabilities);
}
@Override
diff --git a/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java b/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java
index 34344324d0..784d203ab0 100644
--- a/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java
+++ b/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java
@@ -14,6 +14,7 @@ public class WindowElement extends com.vaadin.testbench.elements.WindowElement {
private final String restoreBoxClass = "v-window-restorebox";
private final String maximizeBoxClass = "v-window-maximizebox";
+ private final String closeBoxClass = "v-window-closebox";
public void restore() {
if (isMaximized()) {
@@ -63,4 +64,13 @@ public class WindowElement extends com.vaadin.testbench.elements.WindowElement {
public String getCaption() {
return findElement(By.className("v-window-header")).getText();
}
+
+ private WebElement getCloseButton() {
+ return findElement(By.className(closeBoxClass));
+ }
+
+ public void close() {
+ getCloseButton().click();
+
+ }
}
diff --git a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java
index 4582123f5f..0a57b77aa3 100644
--- a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java
+++ b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java
@@ -29,6 +29,7 @@ import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.MenuBar;
+import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;
@@ -60,7 +61,10 @@ public class LegacyComponentThemeChange extends AbstractTestUIWithLog {
ThemeResource varyingIcon = new ThemeResource("menubar-theme-icon.png");
MenuBar bar = new MenuBar();
bar.addItem("runo", alwaysTheSameIconImage, null);
- bar.addItem("seletedtheme", varyingIcon, null);
+ bar.addItem("selectedtheme", varyingIcon, null);
+ MenuItem sub = bar.addItem("sub menu", null);
+ sub.addItem("runo", alwaysTheSameIconImage, null);
+ sub.addItem("selectedtheme", varyingIcon, null);
vl.addComponent(bar);
diff --git a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java
index c6593104da..3c992f3af5 100644
--- a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java
+++ b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java
@@ -122,8 +122,22 @@ public class LegacyComponentThemeChangeTest extends MultiBrowserTest {
// The other image should change with the theme
WebElement themeImage = $(MenuBarElement.class).first().findElement(
- By.xpath(".//span[text()='seletedtheme']/img"));
+ By.xpath(".//span[text()='selectedtheme']/img"));
assertAttributePrefix(themeImage, "src", theme);
+
+ WebElement subMenuItem = $(MenuBarElement.class).first().findElement(
+ By.xpath(".//span[text()='sub menu']"));
+ subMenuItem.click();
+
+ WebElement subMenu = findElement(By.className("v-menubar-popup"));
+ WebElement subMenuRuno = subMenu.findElement(By
+ .xpath(".//span[text()='runo']/img"));
+ String subMenuRunoImageSrc = subMenuRuno.getAttribute("src");
+ Assert.assertEquals(getThemeURL("runo") + "icons/16/ok.png",
+ subMenuRunoImageSrc);
+ WebElement subMenuThemeImage = subMenu.findElement(By
+ .xpath(".//span[text()='selectedtheme']/img"));
+ assertAttributePrefix(subMenuThemeImage, "src", theme);
}
private void assertAttributePrefix(WebElement element, String attribute,
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Accordions.java b/uitest/src/com/vaadin/tests/themes/valo/Accordions.java
index c32be01d8d..3c7ad2ad33 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Accordions.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Accordions.java
@@ -21,13 +21,14 @@ import com.vaadin.ui.Accordion;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class Accordions extends VerticalLayout implements View {
public Accordions() {
setMargin(true);
Label h1 = new Label("Accordions");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
@@ -38,7 +39,7 @@ public class Accordions extends VerticalLayout implements View {
row.addComponent(getAccordion("Normal"));
Accordion ac = getAccordion("Borderless");
- ac.addStyleName("borderless");
+ ac.addStyleName(ValoTheme.ACCORDION_BORDERLESS);
row.addComponent(ac);
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java b/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java
index dc257fb3ec..eb4be8e0d8 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java
@@ -20,6 +20,7 @@ import com.vaadin.server.ThemeResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
+import com.vaadin.ui.themes.ValoTheme;
/**
* Test UI for image icon in button with 'icon-align-top' style.
@@ -34,7 +35,7 @@ public class AlignTopIconInButton extends AbstractTestUI {
Button button = new Button();
button.setIcon(new ThemeResource("../runo/icons/16/document.png"));
addComponent(button);
- button.addStyleName("icon-align-top");
+ button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_TOP);
button.setCaption("caption");
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java b/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java
index 9ed48896eb..ee88595ba7 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java
@@ -25,6 +25,7 @@ import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
/**
*
@@ -39,11 +40,11 @@ public class ButtonsAndLinks extends VerticalLayout implements View {
setMargin(true);
Label h1 = new Label("Buttons");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -55,30 +56,30 @@ public class ButtonsAndLinks extends VerticalLayout implements View {
row.addComponent(button);
button = new Button("Primary");
- button.addStyleName("primary");
+ button.addStyleName(ValoTheme.BUTTON_PRIMARY);
row.addComponent(button);
button = new Button("Friendly");
- button.addStyleName("friendly");
+ button.addStyleName(ValoTheme.BUTTON_FRIENDLY);
row.addComponent(button);
button = new Button("Danger");
- button.addStyleName("danger");
+ button.addStyleName(ValoTheme.BUTTON_DANGER);
row.addComponent(button);
TestIcon testIcon = new TestIcon(10);
button = new Button("Small");
- button.addStyleName("small");
+ button.addStyleName(ValoTheme.BUTTON_SMALL);
button.setIcon(testIcon.get());
row.addComponent(button);
button = new Button("Large");
- button.addStyleName("large");
+ button.addStyleName(ValoTheme.BUTTON_LARGE);
button.setIcon(testIcon.get());
row.addComponent(button);
button = new Button("Top");
- button.addStyleName("icon-align-top");
+ button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_TOP);
button.setIcon(testIcon.get());
row.addComponent(button);
@@ -87,7 +88,7 @@ public class ButtonsAndLinks extends VerticalLayout implements View {
row.addComponent(button);
button = new Button("Image icon");
- button.addStyleName("icon-align-right");
+ button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_RIGHT);
button.setIcon(testIcon.get(true));
row.addComponent(button);
@@ -97,36 +98,36 @@ public class ButtonsAndLinks extends VerticalLayout implements View {
button = new Button();
button.setIcon(testIcon.get());
- button.addStyleName("icon-only");
+ button.addStyleName(ValoTheme.BUTTON_ICON_ONLY);
row.addComponent(button);
button = new Button("Borderless");
button.setIcon(testIcon.get());
- button.addStyleName("borderless");
+ button.addStyleName(ValoTheme.BUTTON_BORDERLESS);
row.addComponent(button);
button = new Button("Borderless, colored");
button.setIcon(testIcon.get());
- button.addStyleName("borderless-colored");
+ button.addStyleName(ValoTheme.BUTTON_BORDERLESS_COLORED);
row.addComponent(button);
button = new Button("Quiet");
button.setIcon(testIcon.get());
- button.addStyleName("quiet");
+ button.addStyleName(ValoTheme.BUTTON_QUIET);
row.addComponent(button);
button = new Button("Link style");
button.setIcon(testIcon.get());
- button.addStyleName("link");
+ button.addStyleName(ValoTheme.BUTTON_LINK);
row.addComponent(button);
button = new Button("Icon on right");
button.setIcon(testIcon.get());
- button.addStyleName("icon-align-right");
+ button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_RIGHT);
row.addComponent(button);
CssLayout group = new CssLayout();
- group.addStyleName("v-component-group");
+ group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
row.addComponent(group);
button = new Button("One");
@@ -137,22 +138,22 @@ public class ButtonsAndLinks extends VerticalLayout implements View {
group.addComponent(button);
button = new Button("Tiny");
- button.addStyleName("tiny");
+ button.addStyleName(ValoTheme.BUTTON_TINY);
row.addComponent(button);
button = new Button("Huge");
- button.addStyleName("huge");
+ button.addStyleName(ValoTheme.BUTTON_HUGE);
row.addComponent(button);
NativeButton nbutton = new NativeButton("Native");
row.addComponent(nbutton);
h1 = new Label("Links");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -167,16 +168,16 @@ public class ButtonsAndLinks extends VerticalLayout implements View {
row.addComponent(link);
link = new Link("Small", new ExternalResource("https://vaadin.com"));
- link.addStyleName("small");
+ link.addStyleName(ValoTheme.LINK_SMALL);
row.addComponent(link);
link = new Link("Large", new ExternalResource("https://vaadin.com"));
- link.addStyleName("large");
+ link.addStyleName(ValoTheme.LINK_LARGE);
row.addComponent(link);
link = new Link(null, new ExternalResource("https://vaadin.com"));
link.setIcon(testIcon.get());
- link.addStyleName("large");
+ link.addStyleName(ValoTheme.LINK_LARGE);
row.addComponent(link);
link = new Link("Disabled", new ExternalResource("https://vaadin.com"));
diff --git a/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java b/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java
index 280ddf98b7..e18665f2fa 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java
@@ -286,7 +286,7 @@ public class CalendarTest extends GridLayout implements View {
hl.addComponent(captionLabel);
CssLayout group = new CssLayout();
- group.addStyleName("v-component-group");
+ group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
group.addComponent(dayButton);
group.addComponent(weekButton);
group.addComponent(monthButton);
@@ -922,7 +922,7 @@ public class CalendarTest extends GridLayout implements View {
scheduleEventPopup.setModal(true);
scheduleEventPopup.center();
- scheduleEventFieldLayout.addStyleName("light");
+ scheduleEventFieldLayout.addStyleName(ValoTheme.FORMLAYOUT_LIGHT);
scheduleEventFieldLayout.setMargin(false);
layout.addComponent(scheduleEventFieldLayout);
@@ -939,7 +939,7 @@ public class CalendarTest extends GridLayout implements View {
}
}
});
- applyEventButton.addStyleName("primary");
+ applyEventButton.addStyleName(ValoTheme.BUTTON_PRIMARY);
Button cancel = new Button("Cancel", new ClickListener() {
private static final long serialVersionUID = 1L;
@@ -958,7 +958,7 @@ public class CalendarTest extends GridLayout implements View {
deleteCalendarEvent();
}
});
- deleteEventButton.addStyleName("borderless");
+ deleteEventButton.addStyleName(ValoTheme.BUTTON_BORDERLESS);
scheduleEventPopup.addCloseListener(new Window.CloseListener() {
private static final long serialVersionUID = 1L;
@@ -970,7 +970,7 @@ public class CalendarTest extends GridLayout implements View {
});
HorizontalLayout buttons = new HorizontalLayout();
- buttons.addStyleName("v-window-bottom-toolbar");
+ buttons.addStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR);
buttons.setWidth("100%");
buttons.setSpacing(true);
buttons.addComponent(deleteEventButton);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java b/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java
index 9a889b3bda..f77cf9a315 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java
@@ -23,17 +23,18 @@ import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class CheckBoxes extends VerticalLayout implements View {
public CheckBoxes() {
setMargin(true);
Label h1 = new Label("Check Boxes");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -72,11 +73,11 @@ public class CheckBoxes extends VerticalLayout implements View {
row.addComponent(check);
check = new CheckBox("Small", true);
- check.addStyleName("small");
+ check.addStyleName(ValoTheme.CHECKBOX_SMALL);
row.addComponent(check);
check = new CheckBox("Large", true);
- check.addStyleName("large");
+ check.addStyleName(ValoTheme.CHECKBOX_LARGE);
row.addComponent(check);
check = new CheckBox("Disabled", true);
@@ -90,11 +91,11 @@ public class CheckBoxes extends VerticalLayout implements View {
row.addComponent(check);
h1 = new Label("Option Groups");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -124,7 +125,7 @@ public class CheckBoxes extends VerticalLayout implements View {
row.addComponent(options);
options = new OptionGroup("Choose one, small");
- options.addStyleName("small");
+ options.addStyleName(ValoTheme.OPTIONGROUP_SMALL);
options.setMultiSelect(false);
options.addItem("Option One");
options.addItem("Option Two");
@@ -136,7 +137,7 @@ public class CheckBoxes extends VerticalLayout implements View {
row.addComponent(options);
options = new OptionGroup("Choose many, small");
- options.addStyleName("small");
+ options.addStyleName(ValoTheme.OPTIONGROUP_SMALL);
options.setMultiSelect(true);
options.addItem("Option One");
options.addItem("Option Two");
@@ -148,7 +149,7 @@ public class CheckBoxes extends VerticalLayout implements View {
row.addComponent(options);
options = new OptionGroup("Choose one, large");
- options.addStyleName("large");
+ options.addStyleName(ValoTheme.OPTIONGROUP_LARGE);
options.setMultiSelect(false);
options.addItem("Option One");
options.addItem("Option Two");
@@ -160,7 +161,7 @@ public class CheckBoxes extends VerticalLayout implements View {
row.addComponent(options);
options = new OptionGroup("Choose many, large");
- options.addStyleName("large");
+ options.addStyleName(ValoTheme.OPTIONGROUP_LARGE);
options.setMultiSelect(true);
options.addItem("Option One");
options.addItem("Option Two");
@@ -172,7 +173,7 @@ public class CheckBoxes extends VerticalLayout implements View {
row.addComponent(options);
options = new OptionGroup("Horizontal items");
- options.addStyleName("horizontal");
+ options.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL);
options.addItem("Option One");
two = options.addItem("Option Two, with a longer caption");
options.addItem("Option Three");
@@ -185,7 +186,7 @@ public class CheckBoxes extends VerticalLayout implements View {
options = new OptionGroup("Horizontal items, explicit width");
options.setMultiSelect(true);
options.setWidth("500px");
- options.addStyleName("horizontal");
+ options.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL);
options.addItem("Option One");
two = options.addItem("Option Two, with a longer caption");
options.addItem("Option Three");
diff --git a/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java b/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java
index a7fd60ea51..8e32b07ebd 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java
@@ -23,17 +23,18 @@ import com.vaadin.ui.ColorPicker;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class ColorPickers extends VerticalLayout implements View {
public ColorPickers() {
setMargin(true);
Label h1 = new Label("Color Pickers");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java b/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java
index 98a9cad83c..4a88d87cd2 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java
@@ -25,17 +25,18 @@ import com.vaadin.ui.CssLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class ComboBoxes extends VerticalLayout implements View {
public ComboBoxes() {
setMargin(true);
Label h1 = new Label("Combo Boxes");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -52,7 +53,7 @@ public class ComboBoxes extends VerticalLayout implements View {
CssLayout group = new CssLayout();
group.setCaption("Grouped with a Button");
- group.addStyleName("v-component-group");
+ group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
row.addComponent(group);
combo = new ComboBox();
@@ -104,7 +105,7 @@ public class ComboBoxes extends VerticalLayout implements View {
combo.setNullSelectionAllowed(false);
combo.select("Option One");
combo.setComponentError(new UserError("Fix it, now!"));
- combo.addStyleName("borderless");
+ combo.addStyleName(ValoTheme.COMBOBOX_BORDERLESS);
row.addComponent(combo);
combo = new ComboBox("Disabled");
@@ -144,7 +145,7 @@ public class ComboBoxes extends VerticalLayout implements View {
combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false));
combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY);
combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY);
- combo.addStyleName("small");
+ combo.addStyleName(ValoTheme.COMBOBOX_SMALL);
row.addComponent(combo);
combo = new ComboBox("Large");
@@ -152,7 +153,7 @@ public class ComboBoxes extends VerticalLayout implements View {
combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false));
combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY);
combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY);
- combo.addStyleName("large");
+ combo.addStyleName(ValoTheme.COMBOBOX_LARGE);
row.addComponent(combo);
combo = new ComboBox("Borderless");
@@ -160,7 +161,7 @@ public class ComboBoxes extends VerticalLayout implements View {
combo.addItem("Option One");
combo.addItem("Option Two");
combo.addItem("Option Three");
- combo.addStyleName("borderless");
+ combo.addStyleName(ValoTheme.COMBOBOX_BORDERLESS);
row.addComponent(combo);
combo = new ComboBox("Tiny");
@@ -168,7 +169,7 @@ public class ComboBoxes extends VerticalLayout implements View {
combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false));
combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY);
combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY);
- combo.addStyleName("tiny");
+ combo.addStyleName(ValoTheme.COMBOBOX_TINY);
row.addComponent(combo);
combo = new ComboBox("Huge");
@@ -176,7 +177,7 @@ public class ComboBoxes extends VerticalLayout implements View {
combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false));
combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY);
combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY);
- combo.addStyleName("huge");
+ combo.addStyleName(ValoTheme.COMBOBOX_HUGE);
row.addComponent(combo);
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java b/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java
index 52cc43ac28..ea7c42ba2e 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java
@@ -51,13 +51,14 @@ import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.CloseListener;
+import com.vaadin.ui.themes.ValoTheme;
public class CommonParts extends VerticalLayout implements View {
public CommonParts() {
setMargin(true);
Label h1 = new Label("Common UI Elements");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
GridLayout row = new GridLayout(2, 3);
@@ -83,7 +84,7 @@ public class CommonParts extends VerticalLayout implements View {
CssLayout group = new CssLayout();
group.setCaption("Show the loading indicator for…");
- group.addStyleName("v-component-group");
+ group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
content.addComponent(group);
Button loading = new Button("0.8");
loading.addClickListener(new ClickListener() {
@@ -127,13 +128,13 @@ public class CommonParts extends VerticalLayout implements View {
Label spinnerDesc = new Label(
"The theme also provides a mixin that you can use to include a spinner anywhere in your application. Below is a Label with a custom style name, for which the spinner mixin is added.");
- spinnerDesc.addStyleName("small");
+ spinnerDesc.addStyleName(ValoTheme.LABEL_SMALL);
spinnerDesc.setCaption("Spinner");
content.addComponent(spinnerDesc);
if (!ValoThemeUI.isTestMode()) {
Label spinner = new Label();
- spinner.addStyleName("spinner");
+ spinner.addStyleName(ValoTheme.LABEL_SPINNER);
content.addComponent(spinner);
}
@@ -172,7 +173,7 @@ public class CommonParts extends VerticalLayout implements View {
addComponent(title);
description.setInputPrompt("Description for the notification");
- description.addStyleName("small");
+ description.addStyleName(ValoTheme.TEXTAREA_SMALL);
description.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
@@ -217,7 +218,7 @@ public class CommonParts extends VerticalLayout implements View {
type.addItem("Error", typeCommand).setCheckable(true);
type.addItem("System", typeCommand).setCheckable(true);
addComponent(type);
- type.addStyleName("small");
+ type.addStyleName(ValoTheme.MENUBAR_SMALL);
Command styleCommand = new Command() {
@Override
@@ -249,16 +250,16 @@ public class CommonParts extends VerticalLayout implements View {
style.addItem("Small", styleCommand).setCheckable(true);
style.addItem("Closable", styleCommand).setCheckable(true);
addComponent(style);
- style.addStyleName("small");
+ style.addStyleName(ValoTheme.MENUBAR_SMALL);
CssLayout group = new CssLayout();
group.setCaption("Fade delay");
- group.addStyleName("v-component-group");
+ group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
addComponent(group);
delay.setInputPrompt("Infinite");
- delay.addStyleName("align-right");
- delay.addStyleName("small");
+ delay.addStyleName(ValoTheme.TEXTFIELD_ALIGN_RIGHT);
+ delay.addStyleName(ValoTheme.TEXTFIELD_SMALL);
delay.setWidth("7em");
delay.addValueChangeListener(new ValueChangeListener() {
@Override
@@ -284,8 +285,8 @@ public class CommonParts extends VerticalLayout implements View {
});
clear.setIcon(FontAwesome.TIMES_CIRCLE);
clear.addStyleName("last");
- clear.addStyleName("small");
- clear.addStyleName("icon-only");
+ clear.addStyleName(ValoTheme.BUTTON_SMALL);
+ clear.addStyleName(ValoTheme.BUTTON_ICON_ONLY);
group.addComponent(clear);
group.addComponent(new Label("&nbsp; msec", ContentMode.HTML));
@@ -301,7 +302,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -311,7 +312,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -321,7 +322,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -331,7 +332,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -341,7 +342,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -351,7 +352,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -361,7 +362,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -371,7 +372,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
pos = new Button("", new ClickListener() {
@@ -381,7 +382,7 @@ public class CommonParts extends VerticalLayout implements View {
notification.show(Page.getCurrent());
}
});
- pos.addStyleName("small");
+ pos.addStyleName(ValoTheme.BUTTON_SMALL);
grid.addComponent(pos);
}
@@ -397,35 +398,35 @@ public class CommonParts extends VerticalLayout implements View {
{
setSpacing(true);
setMargin(true);
- addStyleName("wrapping");
+ addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
addComponent(new Label(
"Try out different tooltips/descriptions by hovering over the labels."));
Label label = new Label("Simple");
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
label.setDescription("Simple tooltip message");
addComponent(label);
label = new Label("Long");
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
label.setDescription("Long tooltip message. Inmensae subtilitatis, obscuris et malesuada fames. Salutantibus vitae elit libero, a pharetra augue.");
addComponent(label);
label = new Label("HTML tooltip");
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
label.setDescription("<div><h1>Ut enim ad minim veniam, quis nostrud exercitation</h1><p><span>Morbi fringilla convallis sapien, id pulvinar odio volutpat.</span> <span>Vivamus sagittis lacus vel augue laoreet rutrum faucibus.</span> <span>Donec sed odio operae, eu vulputate felis rhoncus.</span> <span>At nos hinc posthac, sitientis piros Afros.</span> <span>Tu quoque, Brute, fili mi, nihil timor populi, nihil!</span></p><p><span>Gallia est omnis divisa in partes tres, quarum.</span> <span>Praeterea iter est quasdam res quas ex communi.</span> <span>Cum ceteris in veneratione tui montes, nascetur mus.</span> <span>Quam temere in vitiis, legem sancimus haerentia.</span> <span>Idque Caesaris facere voluntate liceret: sese habere.</span></p></div>");
addComponent(label);
label = new Label("With an error message");
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
label.setDescription("Simple tooltip message");
label.setComponentError(new UserError(
"Something terrible has happened"));
addComponent(label);
label = new Label("With a long error message");
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
label.setDescription("Simple tooltip message");
label.setComponentError(new UserError(
"<h2>Contra legem facit qui id facit quod lex prohibet <span>Tityre, tu patulae recubans sub tegmine fagi dolor.</span> <span>Tityre, tu patulae recubans sub tegmine fagi dolor.</span> <span>Prima luce, cum quibus mons aliud consensu ab eo.</span> <span>Quid securi etiam tamquam eu fugiat nulla pariatur.</span> <span>Fabio vel iudice vincam, sunt in culpa qui officia.</span> <span>Nihil hic munitissimus habendi senatus locus, nihil horum?</span></p><p><span>Plura mihi bona sunt, inclinet, amari petere vellent.</span> <span>Integer legentibus erat a ante historiarum dapibus.</span> <span>Quam diu etiam furor iste tuus nos eludet?</span> <span>Nec dubitamus multa iter quae et nos invenerat.</span> <span>Quisque ut dolor gravida, placerat libero vel, euismod.</span> <span>Quae vero auctorem tractata ab fiducia dicuntur.</span></h2>",
@@ -434,7 +435,7 @@ public class CommonParts extends VerticalLayout implements View {
addComponent(label);
label = new Label("Error message only");
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
label.setComponentError(new UserError(
"Something terrible has happened"));
addComponent(label);
@@ -479,7 +480,7 @@ public class CommonParts extends VerticalLayout implements View {
Alignment.TOP_RIGHT);
toolbar = toolbarLayout;
}
- toolbar.addStyleName("v-window-top-toolbar");
+ toolbar.addStyleName(ValoTheme.WINDOW_TOP_TOOLBAR);
root.addComponent(toolbar);
}
@@ -498,7 +499,7 @@ public class CommonParts extends VerticalLayout implements View {
"Another");
tabs.addTab(new Label("&nbsp;", ContentMode.HTML),
"One more");
- tabs.addStyleName("padded-tabbar");
+ tabs.addStyleName(ValoTheme.TABSHEET_PADDED_TABBAR);
tabs.addSelectedTabChangeListener(new SelectedTabChangeListener() {
@Override
public void selectedTabChange(
@@ -514,9 +515,9 @@ public class CommonParts extends VerticalLayout implements View {
} else if (!autoHeight) {
Panel p = new Panel();
p.setSizeFull();
- p.addStyleName("borderless");
+ p.addStyleName(ValoTheme.PANEL_BORDERLESS);
if (!toolbarVisible || !toolbarLayout) {
- p.addStyleName("scroll-divider");
+ p.addStyleName(ValoTheme.PANEL_SCROLL_INDICATOR);
}
VerticalLayout l = new VerticalLayout();
l.addComponent(new Label(
@@ -538,13 +539,13 @@ public class CommonParts extends VerticalLayout implements View {
HorizontalLayout footer = new HorizontalLayout();
footer.setWidth("100%");
footer.setSpacing(true);
- footer.addStyleName("v-window-bottom-toolbar");
+ footer.addStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR);
Label footerText = new Label("Footer text");
footerText.setSizeUndefined();
Button ok = new Button("OK");
- ok.addStyleName("primary");
+ ok.addStyleName(ValoTheme.BUTTON_PRIMARY);
Button cancel = new Button("Cancel");
@@ -614,7 +615,7 @@ public class CommonParts extends VerticalLayout implements View {
if (selectedItem.getText()
.equals("Borderless Toolbars")) {
- toolbarStyle = selectedItem.isChecked() ? "borderless"
+ toolbarStyle = selectedItem.isChecked() ? ValoTheme.MENUBAR_BORDERLESS
: null;
}
@@ -630,7 +631,7 @@ public class CommonParts extends VerticalLayout implements View {
MenuItem option = options.addItem("Footer", optionsCommand);
option.setCheckable(true);
option.setChecked(true);
- options.addStyleName("small");
+ options.addStyleName(ValoTheme.MENUBAR_SMALL);
addComponent(options);
options = new MenuBar();
@@ -643,7 +644,7 @@ public class CommonParts extends VerticalLayout implements View {
.setCheckable(true);
options.addItem("Borderless Toolbars", optionsCommand)
.setCheckable(true);
- options.addStyleName("small");
+ options.addStyleName(ValoTheme.MENUBAR_SMALL);
addComponent(options);
Command optionsCommand2 = new Command() {
@@ -671,7 +672,7 @@ public class CommonParts extends VerticalLayout implements View {
options.addItem("Resizable", optionsCommand2)
.setCheckable(true);
options.addItem("Modal", optionsCommand2).setCheckable(true);
- options.addStyleName("small");
+ options.addStyleName(ValoTheme.MENUBAR_SMALL);
addComponent(options);
final Button show = new Button("Open Window",
@@ -684,7 +685,7 @@ public class CommonParts extends VerticalLayout implements View {
event.getButton().setEnabled(false);
}
});
- show.addStyleName("primary");
+ show.addStyleName(ValoTheme.BUTTON_PRIMARY);
addComponent(show);
final CheckBox hidden = new CheckBox("Hidden");
diff --git a/uitest/src/com/vaadin/tests/themes/valo/DateFields.java b/uitest/src/com/vaadin/tests/themes/valo/DateFields.java
index 4b29f83621..9c95b7400c 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/DateFields.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/DateFields.java
@@ -35,17 +35,18 @@ import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.InlineDateField;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class DateFields extends VerticalLayout implements View {
public DateFields() {
setMargin(true);
Label h1 = new Label("Date Fields");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -61,12 +62,12 @@ public class DateFields extends VerticalLayout implements View {
date = new DateField("Error, borderless");
setDate(date);
date.setComponentError(new UserError("Fix it, now!"));
- date.addStyleName("borderless");
+ date.addStyleName(ValoTheme.DATEFIELD_BORDERLESS);
row.addComponent(date);
CssLayout group = new CssLayout();
group.setCaption("Grouped with a Button");
- group.addStyleName("v-component-group");
+ group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
row.addComponent(group);
final DateField date2 = new DateField();
@@ -143,19 +144,19 @@ public class DateFields extends VerticalLayout implements View {
date = new DateField("Small");
setDate(date);
date.setResolution(Resolution.DAY);
- date.addStyleName("small");
+ date.addStyleName(ValoTheme.DATEFIELD_SMALL);
row.addComponent(date);
date = new DateField("Large");
setDate(date);
date.setResolution(Resolution.DAY);
- date.addStyleName("large");
+ date.addStyleName(ValoTheme.DATEFIELD_LARGE);
row.addComponent(date);
date = new DateField("Borderless");
setDate(date);
date.setResolution(Resolution.DAY);
- date.addStyleName("borderless");
+ date.addStyleName(ValoTheme.DATEFIELD_BORDERLESS);
row.addComponent(date);
date = new DateField("Week numbers");
@@ -179,13 +180,13 @@ public class DateFields extends VerticalLayout implements View {
date = new DateField("Tiny");
setDate(date);
date.setResolution(Resolution.DAY);
- date.addStyleName("tiny");
+ date.addStyleName(ValoTheme.DATEFIELD_TINY);
row.addComponent(date);
date = new DateField("Huge");
setDate(date);
date.setResolution(Resolution.DAY);
- date.addStyleName("huge");
+ date.addStyleName(ValoTheme.DATEFIELD_HUGE);
row.addComponent(date);
date = new InlineDateField("Date picker");
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Dragging.java b/uitest/src/com/vaadin/tests/themes/valo/Dragging.java
index 27bdea7d8a..8de518be23 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Dragging.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Dragging.java
@@ -46,6 +46,7 @@ import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Notification;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
/**
*
@@ -61,7 +62,7 @@ public class Dragging extends VerticalLayout implements View {
setSpacing(true);
Label h1 = new Label("Dragging Components");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
MenuBar options = new MenuBar();
@@ -74,9 +75,9 @@ public class Dragging extends VerticalLayout implements View {
@Override
public void menuSelected(MenuItem selectedItem) {
if (selectedItem.isChecked()) {
- sample.removeStyleName("no-vertical-drag-hints");
+ sample.removeStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_VERTICAL_DRAG_HINTS);
} else {
- sample.addStyleName("no-vertical-drag-hints");
+ sample.addStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_VERTICAL_DRAG_HINTS);
}
}
});
@@ -87,9 +88,9 @@ public class Dragging extends VerticalLayout implements View {
@Override
public void menuSelected(MenuItem selectedItem) {
if (selectedItem.isChecked()) {
- sample.removeStyleName("no-horizontal-drag-hints");
+ sample.removeStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_HORIZONTAL_DRAG_HINTS);
} else {
- sample.addStyleName("no-horizontal-drag-hints");
+ sample.addStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_HORIZONTAL_DRAG_HINTS);
}
}
});
@@ -100,9 +101,9 @@ public class Dragging extends VerticalLayout implements View {
@Override
public void menuSelected(MenuItem selectedItem) {
if (selectedItem.isChecked()) {
- sample.removeStyleName("no-box-drag-hints");
+ sample.removeStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_BOX_DRAG_HINTS);
} else {
- sample.addStyleName("no-box-drag-hints");
+ sample.addStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_BOX_DRAG_HINTS);
}
}
});
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Forms.java b/uitest/src/com/vaadin/tests/themes/valo/Forms.java
index 90a6c51496..91fe473d60 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Forms.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Forms.java
@@ -36,6 +36,7 @@ import com.vaadin.ui.RichTextArea;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
/**
*
@@ -48,18 +49,18 @@ public class Forms extends VerticalLayout implements View {
setMargin(true);
Label title = new Label("Forms");
- title.addStyleName("h1");
+ title.addStyleName(ValoTheme.LABEL_H1);
addComponent(title);
final FormLayout form = new FormLayout();
form.setMargin(false);
form.setWidth("800px");
- form.addStyleName("light");
+ form.addStyleName(ValoTheme.FORMLAYOUT_LIGHT);
addComponent(form);
Label section = new Label("Personal Info");
- section.addStyleName("h2");
- section.addStyleName("colored");
+ section.addStyleName(ValoTheme.LABEL_H2);
+ section.addStyleName(ValoTheme.LABEL_COLORED);
form.addComponent(section);
StringGenerator sg = new StringGenerator();
@@ -81,12 +82,12 @@ public class Forms extends VerticalLayout implements View {
sex.addItem("Female");
sex.addItem("Male");
sex.select("Male");
- sex.addStyleName("horizontal");
+ sex.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL);
form.addComponent(sex);
section = new Label("Contact Info");
- section.addStyleName("h3");
- section.addStyleName("colored");
+ section.addStyleName(ValoTheme.LABEL_H3);
+ section.addStyleName(ValoTheme.LABEL_COLORED);
form.addComponent(section);
TextField email = new TextField("Email");
@@ -120,14 +121,14 @@ public class Forms extends VerticalLayout implements View {
period.addItem("Montly");
period.setNullSelectionAllowed(false);
period.select("Weekly");
- period.addStyleName("small");
+ period.addStyleName(ValoTheme.COMBOBOX_SMALL);
period.setWidth("10em");
wrap.addComponent(period);
form.addComponent(wrap);
section = new Label("Additional Info");
- section.addStyleName("h4");
- section.addStyleName("colored");
+ section.addStyleName(ValoTheme.LABEL_H4);
+ section.addStyleName(ValoTheme.LABEL_COLORED);
form.addComponent(section);
TextField website = new TextField("Website");
@@ -156,15 +157,15 @@ public class Forms extends VerticalLayout implements View {
if (readOnly) {
bio.setReadOnly(false);
form.setReadOnly(false);
- form.removeStyleName("light");
+ form.removeStyleName(ValoTheme.FORMLAYOUT_LIGHT);
event.getButton().setCaption("Save");
- event.getButton().addStyleName("primary");
+ event.getButton().addStyleName(ValoTheme.BUTTON_PRIMARY);
} else {
bio.setReadOnly(true);
form.setReadOnly(true);
- form.addStyleName("light");
+ form.addStyleName(ValoTheme.FORMLAYOUT_LIGHT);
event.getButton().setCaption("Edit");
- event.getButton().removeStyleName("primary");
+ event.getButton().removeStyleName(ValoTheme.BUTTON_PRIMARY);
}
}
});
@@ -177,7 +178,7 @@ public class Forms extends VerticalLayout implements View {
footer.addComponent(edit);
Label lastModified = new Label("Last modified by you a minute ago");
- lastModified.addStyleName("light");
+ lastModified.addStyleName(ValoTheme.LABEL_LIGHT);
footer.addComponent(lastModified);
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Labels.java b/uitest/src/com/vaadin/tests/themes/valo/Labels.java
index b5bab3a1d3..9954979d50 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Labels.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Labels.java
@@ -23,6 +23,7 @@ import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
/**
*
@@ -34,7 +35,7 @@ public class Labels extends VerticalLayout implements View {
setMargin(true);
Label h1 = new Label("Labels");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout split = new HorizontalLayout();
@@ -46,16 +47,16 @@ public class Labels extends VerticalLayout implements View {
split.addComponent(left);
Label huge = new Label("Huge type for display text.");
- huge.addStyleName("huge");
+ huge.addStyleName(ValoTheme.LABEL_HUGE);
left.addComponent(huge);
Label large = new Label(
"Large type for introductory text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu.");
- large.addStyleName("large");
+ large.addStyleName(ValoTheme.LABEL_LARGE);
left.addComponent(large);
Label h2 = new Label("Subtitle");
- h2.addStyleName("h2");
+ h2.addStyleName(ValoTheme.LABEL_H2);
left.addComponent(h2);
Label normal = new Label(
@@ -64,20 +65,20 @@ public class Labels extends VerticalLayout implements View {
left.addComponent(normal);
Label h3 = new Label("Small Title");
- h3.addStyleName("h3");
+ h3.addStyleName(ValoTheme.LABEL_H3);
left.addComponent(h3);
Label small = new Label(
"Small type for additional text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu.");
- small.addStyleName("small");
+ small.addStyleName(ValoTheme.LABEL_SMALL);
left.addComponent(small);
Label tiny = new Label("Tiny type for minor text.");
- tiny.addStyleName("tiny");
+ tiny.addStyleName(ValoTheme.LABEL_TINY);
left.addComponent(tiny);
Label h4 = new Label("Section Title");
- h4.addStyleName("h4");
+ h4.addStyleName(ValoTheme.LABEL_H4);
left.addComponent(h4);
normal = new Label(
@@ -94,25 +95,25 @@ public class Labels extends VerticalLayout implements View {
Label label = new Label(
"Bold type for prominent text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu.");
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
right.addComponent(label);
label = new Label(
"Light type for subtle text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu.");
- label.addStyleName("light");
+ label.addStyleName(ValoTheme.LABEL_LIGHT);
right.addComponent(label);
label = new Label(
"Colored type for highlighted text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu.");
- label.addStyleName("colored");
+ label.addStyleName(ValoTheme.LABEL_COLORED);
right.addComponent(label);
label = new Label("A label for success");
- label.addStyleName("success");
+ label.addStyleName(ValoTheme.LABEL_SUCCESS);
right.addComponent(label);
label = new Label("A label for failure");
- label.addStyleName("failure");
+ label.addStyleName(ValoTheme.LABEL_FAILURE);
right.addComponent(label);
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java b/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java
index 4a0130931e..fc74166b29 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java
@@ -25,6 +25,7 @@ import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Notification;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class MenuBars extends VerticalLayout implements View {
public MenuBars() {
@@ -32,7 +33,7 @@ public class MenuBars extends VerticalLayout implements View {
setSpacing(true);
Label h1 = new Label("Menu Bars");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
MenuBar menuBar = getMenuBar();
@@ -41,37 +42,37 @@ public class MenuBars extends VerticalLayout implements View {
menuBar = getMenuBar();
menuBar.setCaption("Small style");
- menuBar.addStyleName("small");
+ menuBar.addStyleName(ValoTheme.MENUBAR_SMALL);
addComponent(menuBar);
menuBar = getMenuBar();
menuBar.setCaption("Borderless style");
- menuBar.addStyleName("borderless");
+ menuBar.addStyleName(ValoTheme.MENUBAR_BORDERLESS);
addComponent(menuBar);
menuBar = getMenuBar();
menuBar.setCaption("Small borderless style");
- menuBar.addStyleName("borderless");
- menuBar.addStyleName("small");
+ menuBar.addStyleName(ValoTheme.MENUBAR_BORDERLESS);
+ menuBar.addStyleName(ValoTheme.MENUBAR_SMALL);
addComponent(menuBar);
Label h2 = new Label("Drop Down Button");
- h2.addStyleName("h2");
+ h2.addStyleName(ValoTheme.LABEL_H2);
addComponent(h2);
HorizontalLayout wrap = new HorizontalLayout();
- wrap.addStyleName("wrapping");
+ wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
wrap.setSpacing(true);
addComponent(wrap);
wrap.addComponent(getMenuButton("Normal", false));
MenuBar split = getMenuButton("Small", false);
- split.addStyleName("small");
+ split.addStyleName(ValoTheme.MENUBAR_SMALL);
wrap.addComponent(split);
split = getMenuButton("Borderless", false);
- split.addStyleName("borderless");
+ split.addStyleName(ValoTheme.MENUBAR_BORDERLESS);
wrap.addComponent(split);
split = getMenuButton("Themed", false);
@@ -80,26 +81,26 @@ public class MenuBars extends VerticalLayout implements View {
split = getMenuButton("Small", false);
split.addStyleName("color1");
- split.addStyleName("small");
+ split.addStyleName(ValoTheme.MENUBAR_SMALL);
wrap.addComponent(split);
h2 = new Label("Split Button");
- h2.addStyleName("h2");
+ h2.addStyleName(ValoTheme.LABEL_H2);
addComponent(h2);
wrap = new HorizontalLayout();
- wrap.addStyleName("wrapping");
+ wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
wrap.setSpacing(true);
addComponent(wrap);
wrap.addComponent(getMenuButton("Normal", true));
split = getMenuButton("Small", true);
- split.addStyleName("small");
+ split.addStyleName(ValoTheme.MENUBAR_SMALL);
wrap.addComponent(split);
split = getMenuButton("Borderless", true);
- split.addStyleName("borderless");
+ split.addStyleName(ValoTheme.MENUBAR_BORDERLESS);
wrap.addComponent(split);
split = getMenuButton("Themed", true);
@@ -108,7 +109,7 @@ public class MenuBars extends VerticalLayout implements View {
split = getMenuButton("Small", true);
split.addStyleName("color1");
- split.addStyleName("small");
+ split.addStyleName(ValoTheme.MENUBAR_SMALL);
wrap.addComponent(split);
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java b/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java
index 284f7c8d6e..e9c1c78049 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java
@@ -23,17 +23,18 @@ import com.vaadin.ui.ListSelect;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.TwinColSelect;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class NativeSelects extends VerticalLayout implements View {
public NativeSelects() {
setMargin(true);
Label h1 = new Label("Selects");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java b/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java
index 7adae9ce65..5f9542b6f3 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java
@@ -27,6 +27,7 @@ import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
+import com.vaadin.ui.themes.ValoTheme;
/**
* Test for H1 and P elements styles in Notifications.
@@ -45,7 +46,8 @@ public class NotificationStyleTest extends MultiBrowserTest {
waitUntil(notificationPresentCondition(), 2);
WebElement notification = findElement(By.className("v-Notification"));
- List<WebElement> headers = notification.findElements(By.tagName("h1"));
+ List<WebElement> headers = notification.findElements(By
+ .tagName(ValoTheme.LABEL_H1));
String textAlign = headers.get(0).getCssValue("text-align");
String textAlignInnerHeader = headers.get(1).getCssValue("text-align");
Assert.assertNotEquals("Styles for notification defined h1 tag "
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Panels.java b/uitest/src/com/vaadin/tests/themes/valo/Panels.java
index 8a17244693..d98daf7b05 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Panels.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Panels.java
@@ -27,17 +27,18 @@ import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class Panels extends VerticalLayout implements View {
public Panels() {
setMargin(true);
Label h1 = new Label("Panels & Layout panels");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
TestIcon testIcon = new TestIcon(60);
@@ -74,33 +75,33 @@ public class Panels extends VerticalLayout implements View {
panel = new Panel("Borderless style");
panel.setIcon(testIcon.get());
- panel.addStyleName("borderless");
+ panel.addStyleName(ValoTheme.PANEL_BORDERLESS);
panel.setContent(panelContent());
row.addComponent(panel);
panel = new Panel("Borderless + scroll divider");
panel.setIcon(testIcon.get());
- panel.addStyleName("borderless");
- panel.addStyleName("scroll-divider");
+ panel.addStyleName(ValoTheme.PANEL_BORDERLESS);
+ panel.addStyleName(ValoTheme.PANEL_SCROLL_INDICATOR);
panel.setContent(panelContentScroll());
panel.setHeight("17em");
row.addComponent(panel);
panel = new Panel("Well style");
panel.setIcon(testIcon.get());
- panel.addStyleName("well");
+ panel.addStyleName(ValoTheme.PANEL_WELL);
panel.setContent(panelContent());
row.addComponent(panel);
CssLayout layout = new CssLayout();
layout.setIcon(testIcon.get());
layout.setCaption("Panel style layout");
- layout.addStyleName("card");
+ layout.addStyleName(ValoTheme.LAYOUT_CARD);
layout.addComponent(panelContent());
row.addComponent(layout);
layout = new CssLayout();
- layout.addStyleName("card");
+ layout.addStyleName(ValoTheme.LAYOUT_CARD);
row.addComponent(layout);
HorizontalLayout panelCaption = new HorizontalLayout();
panelCaption.addStyleName("v-panel-caption");
@@ -112,13 +113,13 @@ public class Panels extends VerticalLayout implements View {
Button action = new Button();
action.setIcon(FontAwesome.PENCIL);
- action.addStyleName("borderless-colored");
- action.addStyleName("small");
- action.addStyleName("icon-only");
+ action.addStyleName(ValoTheme.BUTTON_BORDERLESS_COLORED);
+ action.addStyleName(ValoTheme.BUTTON_SMALL);
+ action.addStyleName(ValoTheme.BUTTON_ICON_ONLY);
panelCaption.addComponent(action);
MenuBar dropdown = new MenuBar();
- dropdown.addStyleName("borderless");
- dropdown.addStyleName("small");
+ dropdown.addStyleName(ValoTheme.MENUBAR_BORDERLESS);
+ dropdown.addStyleName(ValoTheme.MENUBAR_SMALL);
MenuItem addItem = dropdown.addItem("", FontAwesome.CHEVRON_DOWN, null);
addItem.setStyleName("icon-only");
addItem.addItem("Settings", null);
@@ -134,7 +135,7 @@ public class Panels extends VerticalLayout implements View {
layout = new CssLayout();
layout.setIcon(testIcon.get());
layout.setCaption("Well style layout");
- layout.addStyleName("well");
+ layout.addStyleName(ValoTheme.LAYOUT_WELL);
layout.addComponent(panelContent());
row.addComponent(layout);
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java b/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java
index c15270400c..58988c06d6 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java
@@ -24,17 +24,18 @@ import com.vaadin.ui.Label;
import com.vaadin.ui.PopupView;
import com.vaadin.ui.PopupView.Content;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class PopupViews extends VerticalLayout implements View {
public PopupViews() {
setMargin(true);
Label h1 = new Label("Popup Views");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Sliders.java b/uitest/src/com/vaadin/tests/themes/valo/Sliders.java
index 8ed846e39f..9642cb5ccf 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Sliders.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Sliders.java
@@ -23,17 +23,18 @@ import com.vaadin.ui.Label;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.Slider;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class Sliders extends VerticalLayout implements View {
public Sliders() {
setMargin(true);
Label h1 = new Label("Sliders");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -67,7 +68,7 @@ public class Sliders extends VerticalLayout implements View {
slider = new Slider("No indicator");
slider.setValue(50.0);
slider.setWidth("200px");
- slider.addStyleName("no-indicator");
+ slider.addStyleName(ValoTheme.SLIDER_NO_INDICATOR);
row.addComponent(slider);
slider = new Slider("With ticks (not in IE8 & IE9)");
@@ -119,7 +120,7 @@ public class Sliders extends VerticalLayout implements View {
slider = new Slider("No indicator");
slider.setValue(50.0);
slider.setHeight("200px");
- slider.addStyleName("no-indicator");
+ slider.addStyleName(ValoTheme.SLIDER_NO_INDICATOR);
slider.setOrientation(SliderOrientation.VERTICAL);
row.addComponent(slider);
@@ -137,11 +138,11 @@ public class Sliders extends VerticalLayout implements View {
row.addComponent(slider);
h1 = new Label("Progress Bars");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -154,7 +155,7 @@ public class Sliders extends VerticalLayout implements View {
pb2 = new ProgressBar();
pb2.setCaption("Point style");
pb2.setWidth("300px");
- pb2.addStyleName("point");
+ pb2.addStyleName(ValoTheme.PROGRESSBAR_POINT);
// pb2.setValue(0.6f);
row.addComponent(pb2);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java b/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java
index 9a6d86ae04..4983bc5813 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java
@@ -23,20 +23,21 @@ import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.VerticalSplitPanel;
+import com.vaadin.ui.themes.ValoTheme;
public class SplitPanels extends VerticalLayout implements View {
public SplitPanels() {
setMargin(true);
Label h1 = new Label("Split Panels");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
addComponent(new Label(
"Outlines are just to show the areas of the SplitPanels. They are not part of the actual component style."));
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
row.setMargin(new MarginInfo(true, false, false, false));
addComponent(row);
@@ -61,7 +62,7 @@ public class SplitPanels extends VerticalLayout implements View {
sp.setCaption("Large style");
sp.setWidth("300px");
sp.setHeight("200px");
- sp.addStyleName("large");
+ sp.addStyleName(ValoTheme.SPLITPANEL_LARGE);
sp.setFirstComponent(getContent());
sp.setSecondComponent(getContent());
row.addComponent(sp);
@@ -70,7 +71,7 @@ public class SplitPanels extends VerticalLayout implements View {
sp2.setCaption("Large style");
sp2.setWidth("300px");
sp2.setHeight("200px");
- sp2.addStyleName("large");
+ sp2.addStyleName(ValoTheme.SPLITPANEL_LARGE);
sp2.setFirstComponent(getContent());
sp2.setSecondComponent(getContent());
row.addComponent(sp2);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Tables.java b/uitest/src/com/vaadin/tests/themes/valo/Tables.java
index fb6638ee7d..071e6b746a 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Tables.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Tables.java
@@ -42,6 +42,7 @@ import com.vaadin.ui.Table.TableDragMode;
import com.vaadin.ui.TextField;
import com.vaadin.ui.TreeTable;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class Tables extends VerticalLayout implements View {
@@ -72,11 +73,11 @@ public class Tables extends VerticalLayout implements View {
setSpacing(true);
Label h1 = new Label("Tables");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout wrap = new HorizontalLayout();
- wrap.addStyleName("wrapping");
+ wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
wrap.setSpacing(true);
addComponent(wrap);
@@ -189,9 +190,9 @@ public class Tables extends VerticalLayout implements View {
Object columnId) {
TextField tf = new TextField();
tf.setInputPrompt("Type here…");
- // tf.addStyleName("compact");
+ // tf.addStyleName(ValoTheme.TABLE_COMPACT);
if ((Integer) itemId % 2 == 0) {
- tf.addStyleName("borderless");
+ tf.addStyleName(ValoTheme.TABLE_BORDERLESS);
}
return tf;
}
@@ -203,9 +204,9 @@ public class Tables extends VerticalLayout implements View {
public Object generateCell(Table source, Object itemId,
Object columnId) {
DateField tf = new DateField();
- tf.addStyleName("compact");
+ tf.addStyleName(ValoTheme.TABLE_COMPACT);
if ((Integer) itemId % 2 == 0) {
- tf.addStyleName("borderless");
+ tf.addStyleName(ValoTheme.DATEFIELD_BORDERLESS);
}
return tf;
}
@@ -218,9 +219,9 @@ public class Tables extends VerticalLayout implements View {
Object columnId) {
ComboBox tf = new ComboBox();
tf.setInputPrompt("Select");
- tf.addStyleName("compact");
+ tf.addStyleName(ValoTheme.TABLE_COMPACT);
if ((Integer) itemId % 2 == 0) {
- tf.addStyleName("borderless");
+ tf.addStyleName(ValoTheme.DATEFIELD_BORDERLESS);
}
return tf;
}
@@ -232,7 +233,7 @@ public class Tables extends VerticalLayout implements View {
public Object generateCell(Table source, Object itemId,
Object columnId) {
Button b = new Button("Button");
- b.addStyleName("small");
+ b.addStyleName(ValoTheme.BUTTON_SMALL);
return b;
}
});
@@ -244,7 +245,7 @@ public class Tables extends VerticalLayout implements View {
Object columnId) {
Label label = new Label("Label component");
label.setSizeUndefined();
- label.addStyleName("bold");
+ label.addStyleName(ValoTheme.LABEL_BOLD);
return label;
}
});
@@ -267,7 +268,7 @@ public class Tables extends VerticalLayout implements View {
OptionGroup op = new OptionGroup();
op.addItem("Male");
op.addItem("Female");
- op.addStyleName("horizontal");
+ op.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL);
return op;
}
});
@@ -321,45 +322,45 @@ public class Tables extends VerticalLayout implements View {
expandRatios ? 1.0f : 0);
if (!stripes) {
- table.addStyleName("no-stripes");
+ table.addStyleName(ValoTheme.TABLE_NO_STRIPES);
} else {
- table.removeStyleName("no-stripes");
+ table.removeStyleName(ValoTheme.TABLE_NO_STRIPES);
}
if (!verticalLines) {
- table.addStyleName("no-vertical-lines");
+ table.addStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES);
} else {
- table.removeStyleName("no-vertical-lines");
+ table.removeStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES);
}
if (!horizontalLines) {
- table.addStyleName("no-horizontal-lines");
+ table.addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES);
} else {
- table.removeStyleName("no-horizontal-lines");
+ table.removeStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES);
}
if (borderless) {
- table.addStyleName("borderless");
+ table.addStyleName(ValoTheme.TABLE_BORDERLESS);
} else {
- table.removeStyleName("borderless");
+ table.removeStyleName(ValoTheme.TABLE_BORDERLESS);
}
if (!headers) {
- table.addStyleName("no-header");
+ table.addStyleName(ValoTheme.TABLE_NO_HEADER);
} else {
- table.removeStyleName("no-header");
+ table.removeStyleName(ValoTheme.TABLE_NO_HEADER);
}
if (compact) {
- table.addStyleName("compact");
+ table.addStyleName(ValoTheme.TABLE_COMPACT);
} else {
- table.removeStyleName("compact");
+ table.removeStyleName(ValoTheme.TABLE_COMPACT);
}
if (small) {
- table.addStyleName("small");
+ table.addStyleName(ValoTheme.TABLE_SMALL);
} else {
- table.removeStyleName("small");
+ table.removeStyleName(ValoTheme.TABLE_SMALL);
}
if (!rowIndex && !rowCaption && rowIcon) {
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java b/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java
index 5e77292471..421da5ffe7 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java
@@ -28,6 +28,7 @@ import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
import com.vaadin.ui.TabSheet.SelectedTabChangeListener;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class Tabsheets extends VerticalLayout implements View {
@@ -37,12 +38,12 @@ public class Tabsheets extends VerticalLayout implements View {
setMargin(true);
Label h1 = new Label("Tabs");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout wrap = new HorizontalLayout();
wrap.setSpacing(true);
- wrap.addStyleName("wrapping");
+ wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
addComponent(wrap);
final CheckBox closable = new CheckBox("Closable");
@@ -66,12 +67,12 @@ public class Tabsheets extends VerticalLayout implements View {
wrap.addComponent(disable);
Label h3 = new Label("Additional Styles");
- h3.addStyleName("h3");
+ h3.addStyleName(ValoTheme.LABEL_H3);
addComponent(h3);
wrap = new HorizontalLayout();
wrap.setSpacing(true);
- wrap.addStyleName("wrapping");
+ wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
wrap.setMargin(new MarginInfo(false, false, true, false));
addComponent(wrap);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/TextFields.java b/uitest/src/com/vaadin/tests/themes/valo/TextFields.java
index 347a683673..be6e430b23 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/TextFields.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/TextFields.java
@@ -28,6 +28,7 @@ import com.vaadin.ui.RichTextArea;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class TextFields extends VerticalLayout implements View {
private TestIcon testIcon = new TestIcon(140);
@@ -36,11 +37,11 @@ public class TextFields extends VerticalLayout implements View {
setMargin(true);
Label h1 = new Label("Text Fields");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -72,7 +73,7 @@ public class TextFields extends VerticalLayout implements View {
tf = new TextField("Error, borderless");
tf.setValue("Something’s wrong");
tf.setComponentError(new UserError("Fix it, now!"));
- tf.addStyleName("borderless");
+ tf.addStyleName(ValoTheme.TEXTFIELD_BORDERLESS);
row.addComponent(tf);
tf = new TextField("Read-only");
@@ -83,121 +84,121 @@ public class TextFields extends VerticalLayout implements View {
tf = new TextField("Small");
tf.setValue("Field value");
- tf.addStyleName("small");
+ tf.addStyleName(ValoTheme.TEXTFIELD_SMALL);
row.addComponent(tf);
tf = new TextField("Large");
tf.setValue("Field value");
- tf.addStyleName("large");
+ tf.addStyleName(ValoTheme.TEXTFIELD_LARGE);
tf.setIcon(testIcon.get(true));
row.addComponent(tf);
tf = new TextField("Icon inside");
tf.setInputPrompt("Ooh, an icon");
- tf.addStyleName("inline-icon");
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
tf.setIcon(testIcon.get());
row.addComponent(tf);
tf = new TextField("Large, Icon inside");
tf.setInputPrompt("Ooh, an icon");
- tf.addStyleName("large");
- tf.addStyleName("inline-icon");
+ tf.addStyleName(ValoTheme.TEXTFIELD_LARGE);
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
tf.setIcon(testIcon.get());
row.addComponent(tf);
tf = new TextField("Small, Icon inside");
tf.setInputPrompt("Ooh, an icon");
- tf.addStyleName("small");
- tf.addStyleName("inline-icon");
+ tf.addStyleName(ValoTheme.TEXTFIELD_SMALL);
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
tf.setIcon(testIcon.get());
row.addComponent(tf);
tf = new TextField("16px supported by default");
tf.setInputPrompt("Image icon");
- tf.addStyleName("inline-icon");
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
tf.setIcon(testIcon.get(true, 16));
row.addComponent(tf);
tf = new TextField();
tf.setValue("Font, no caption");
- tf.addStyleName("inline-icon");
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
tf.setIcon(testIcon.get());
row.addComponent(tf);
tf = new TextField();
tf.setValue("Image, no caption");
- tf.addStyleName("inline-icon");
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
tf.setIcon(testIcon.get(true, 16));
row.addComponent(tf);
CssLayout group = new CssLayout();
- group.addStyleName("v-component-group");
+ group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
row.addComponent(group);
tf = new TextField();
tf.setInputPrompt("Grouped with a button");
- tf.addStyleName("inline-icon");
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
tf.setIcon(testIcon.get());
tf.setWidth("260px");
group.addComponent(tf);
Button button = new Button("Do It");
- // button.addStyleName("primary");
+ // button.addStyleName(ValoTheme.BUTTON_PRIMARY);
group.addComponent(button);
tf = new TextField("Borderless");
tf.setInputPrompt("Write here…");
- tf.addStyleName("inline-icon");
- tf.addStyleName("borderless");
+ tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
+ tf.addStyleName(ValoTheme.TEXTFIELD_BORDERLESS);
tf.setIcon(testIcon.get());
row.addComponent(tf);
tf = new TextField("Right-aligned");
tf.setValue("1,234");
- tf.addStyleName("align-right");
+ tf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_RIGHT);
row.addComponent(tf);
tf = new TextField("Centered");
tf.setInputPrompt("Guess what?");
- tf.addStyleName("align-center");
+ tf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_CENTER);
row.addComponent(tf);
PasswordField pwf = new PasswordField("Password");
pwf.setInputPrompt("Secret words");
- pwf.addStyleName("inline-icon");
+ pwf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
pwf.setIcon(FontAwesome.LOCK);
row.addComponent(pwf);
pwf = new PasswordField("Password, right-aligned");
pwf.setInputPrompt("Secret words");
- pwf.addStyleName("inline-icon");
- pwf.addStyleName("align-right");
+ pwf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
+ pwf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_RIGHT);
pwf.setIcon(FontAwesome.LOCK);
row.addComponent(pwf);
pwf = new PasswordField("Password, centered");
pwf.setInputPrompt("Secret words");
- pwf.addStyleName("inline-icon");
- pwf.addStyleName("align-center");
+ pwf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON);
+ pwf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_CENTER);
pwf.setIcon(FontAwesome.LOCK);
row.addComponent(pwf);
tf = new TextField("Tiny");
tf.setValue("Field value");
- tf.addStyleName("tiny");
+ tf.addStyleName(ValoTheme.TEXTFIELD_TINY);
row.addComponent(tf);
tf = new TextField("Huge");
tf.setValue("Field value");
- tf.addStyleName("huge");
+ tf.addStyleName(ValoTheme.TEXTFIELD_HUGE);
row.addComponent(tf);
h1 = new Label("Text Areas");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
@@ -228,37 +229,37 @@ public class TextFields extends VerticalLayout implements View {
row.addComponent(ta);
ta = new TextArea("Small");
- ta.addStyleName("small");
+ ta.addStyleName(ValoTheme.TEXTAREA_SMALL);
ta.setInputPrompt("Write your comment…");
row.addComponent(ta);
ta = new TextArea("Large");
- ta.addStyleName("large");
+ ta.addStyleName(ValoTheme.TEXTAREA_LARGE);
ta.setInputPrompt("Write your comment…");
row.addComponent(ta);
ta = new TextArea("Borderless");
- ta.addStyleName("borderless");
+ ta.addStyleName(ValoTheme.TEXTAREA_BORDERLESS);
ta.setInputPrompt("Write your comment…");
row.addComponent(ta);
ta = new TextArea("Right-aligned");
- ta.addStyleName("align-right");
+ ta.addStyleName(ValoTheme.TEXTAREA_ALIGN_RIGHT);
ta.setValue("Field value, spanning multiple lines of text");
row.addComponent(ta);
ta = new TextArea("Centered");
- ta.addStyleName("align-center");
+ ta.addStyleName(ValoTheme.TEXTAREA_ALIGN_CENTER);
ta.setValue("Field value, spanning multiple lines of text");
row.addComponent(ta);
ta = new TextArea("Tiny");
- ta.addStyleName("tiny");
+ ta.addStyleName(ValoTheme.TEXTAREA_TINY);
ta.setInputPrompt("Write your comment…");
row.addComponent(ta);
ta = new TextArea("Huge");
- ta.addStyleName("huge");
+ ta.addStyleName(ValoTheme.TEXTAREA_HUGE);
ta.setInputPrompt("Write your comment…");
row.addComponent(ta);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/Trees.java b/uitest/src/com/vaadin/tests/themes/valo/Trees.java
index cb5657660a..02846d8921 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/Trees.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/Trees.java
@@ -28,17 +28,18 @@ import com.vaadin.ui.Notification;
import com.vaadin.ui.Tree;
import com.vaadin.ui.Tree.TreeDragMode;
import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.ValoTheme;
public class Trees extends VerticalLayout implements View {
public Trees() {
setMargin(true);
Label h1 = new Label("Trees");
- h1.addStyleName("h1");
+ h1.addStyleName(ValoTheme.LABEL_H1);
addComponent(h1);
HorizontalLayout row = new HorizontalLayout();
- row.addStyleName("wrapping");
+ row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING);
row.setSpacing(true);
addComponent(row);
diff --git a/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java b/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java
index 3a3baa686c..0e62f983a6 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java
@@ -19,6 +19,7 @@ import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.themes.ValoTheme;
/**
*
@@ -34,7 +35,7 @@ public class ValoMenuLayout extends HorizontalLayout {
public ValoMenuLayout() {
setSizeFull();
- menuArea.setPrimaryStyleName("valo-menu");
+ menuArea.setPrimaryStyleName(ValoTheme.MENU_ROOT);
contentArea.setPrimaryStyleName("valo-content");
contentArea.addStyleName("v-scrollable");
@@ -49,7 +50,7 @@ public class ValoMenuLayout extends HorizontalLayout {
}
public void addMenu(Component menu) {
- menu.addStyleName("valo-menu-part");
+ menu.addStyleName(ValoTheme.MENU_PART);
menuArea.addComponent(menu);
}
diff --git a/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java b/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java
index 988b3487bd..3bf6fd7ca3 100644
--- a/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java
+++ b/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java
@@ -194,29 +194,29 @@ public class ValoThemeUI extends UI {
Component buildTestMenu() {
CssLayout menu = new CssLayout();
- menu.addStyleName("large-icons");
+ menu.addStyleName(ValoTheme.MENU_PART_LARGE_ICONS);
Label logo = new Label("Va");
logo.setSizeUndefined();
- logo.setPrimaryStyleName("valo-menu-logo");
+ logo.setPrimaryStyleName(ValoTheme.MENU_LOGO);
menu.addComponent(logo);
Button b = new Button(
"Reference <span class=\"valo-menu-badge\">3</span>");
b.setIcon(FontAwesome.TH_LIST);
- b.setPrimaryStyleName("valo-menu-item");
+ b.setPrimaryStyleName(ValoTheme.MENU_ITEM);
b.addStyleName("selected");
b.setHtmlContentAllowed(true);
menu.addComponent(b);
b = new Button("API");
b.setIcon(FontAwesome.BOOK);
- b.setPrimaryStyleName("valo-menu-item");
+ b.setPrimaryStyleName(ValoTheme.MENU_ITEM);
menu.addComponent(b);
b = new Button("Examples <span class=\"valo-menu-badge\">12</span>");
b.setIcon(FontAwesome.TABLE);
- b.setPrimaryStyleName("valo-menu-item");
+ b.setPrimaryStyleName(ValoTheme.MENU_ITEM);
b.setHtmlContentAllowed(true);
menu.addComponent(b);
@@ -250,7 +250,7 @@ public class ValoThemeUI extends UI {
HorizontalLayout top = new HorizontalLayout();
top.setWidth("100%");
top.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
- top.addStyleName("valo-menu-title");
+ top.addStyleName(ValoTheme.MENU_TITLE);
menu.addComponent(top);
menu.addComponent(createThemeSelect());
@@ -297,8 +297,8 @@ public class ValoThemeUI extends UI {
for (final Entry<String, String> item : menuItems.entrySet()) {
if (item.getKey().equals("labels")) {
label = new Label("Components", ContentMode.HTML);
- label.setPrimaryStyleName("valo-menu-subtitle");
- label.addStyleName("h4");
+ label.setPrimaryStyleName(ValoTheme.MENU_SUBTITLE);
+ label.addStyleName(ValoTheme.LABEL_H4);
label.setSizeUndefined();
menuItemsLayout.addComponent(label);
}
@@ -308,8 +308,8 @@ public class ValoThemeUI extends UI {
+ "</span>");
count = 0;
label = new Label("Containers", ContentMode.HTML);
- label.setPrimaryStyleName("valo-menu-subtitle");
- label.addStyleName("h4");
+ label.setPrimaryStyleName(ValoTheme.MENU_SUBTITLE);
+ label.addStyleName(ValoTheme.LABEL_H4);
label.setSizeUndefined();
menuItemsLayout.addComponent(label);
}
@@ -319,8 +319,8 @@ public class ValoThemeUI extends UI {
+ "</span>");
count = 0;
label = new Label("Other", ContentMode.HTML);
- label.setPrimaryStyleName("valo-menu-subtitle");
- label.addStyleName("h4");
+ label.setPrimaryStyleName(ValoTheme.MENU_SUBTITLE);
+ label.addStyleName(ValoTheme.LABEL_H4);
label.setSizeUndefined();
menuItemsLayout.addComponent(label);
}
@@ -335,7 +335,7 @@ public class ValoThemeUI extends UI {
+ " <span class=\"valo-menu-badge\">123</span>");
}
b.setHtmlContentAllowed(true);
- b.setPrimaryStyleName("valo-menu-item");
+ b.setPrimaryStyleName(ValoTheme.MENU_ITEM);
b.setIcon(testIcon.get());
menuItemsLayout.addComponent(b);
count++;
diff --git a/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java
new file mode 100644
index 0000000000..ff470336f5
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java
@@ -0,0 +1,34 @@
+package com.vaadin.tests.tooltip;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.MenuBar;
+
+public class MenuBarTooltip extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ MenuBar menubar = new MenuBar();
+
+ MenuBar.MenuItem menuitem = menubar.addItem("Menu item", null, null);
+ menuitem.setDescription("Menu item description");
+
+ MenuBar.MenuItem submenuitem1 = menuitem.addItem("Submenu item 1", null, null);
+ submenuitem1.setDescription("Submenu item 1 description");
+
+ MenuBar.MenuItem submenuitem2 = menuitem.addItem("Submenu item 2", null, null);
+ submenuitem2.setDescription("Submenu item 2 description");
+
+ addComponent(menubar);
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 14854;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "MenuItem tooltip should have a larger z-index than MenuBar/MenuItem.";
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java
new file mode 100644
index 0000000000..9b2f7d13d6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java
@@ -0,0 +1,46 @@
+package com.vaadin.tests.tooltip;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+import com.vaadin.testbench.elements.MenuBarElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+import com.vaadin.ui.themes.ChameleonTheme;
+import com.vaadin.ui.themes.Reindeer;
+import com.vaadin.ui.themes.Runo;
+import com.vaadin.ui.themes.ValoTheme;
+
+public class MenuBarTooltipTest extends MultiBrowserTest {
+
+ @Test
+ public void toolTipShouldBeOnTopOfMenuItem() {
+ String[] themes = new String[] {
+ ValoTheme.THEME_NAME,
+ Reindeer.THEME_NAME,
+ Runo.THEME_NAME,
+ ChameleonTheme.THEME_NAME
+ };
+
+ for(String theme : themes) {
+ assertZIndices(theme);
+ }
+ }
+
+ public void assertZIndices(String theme) {
+ openTestURL("theme=" + theme);
+
+ $(MenuBarElement.class).first().clickItem("Menu item");
+
+ assertThat(String.format("Invalid z-index for theme %s.", theme),
+ getZIndex("v-tooltip"), greaterThan(getZIndex("v-menubar-popup")));
+ }
+
+ private int getZIndex(String className) {
+ return Integer.parseInt(
+ findElement(By.className(className)).getCssValue("z-index"));
+ }
+
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
index 8a02d91d2c..3878e85193 100644
--- a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
+++ b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
@@ -23,5 +23,6 @@
<generate-with class="com.vaadin.tests.widgetset.rebind.TestWidgetRegistryGenerator">
<when-type-is class="com.vaadin.tests.widgetset.client.TestWidgetConnector.TestWidgetRegistry" />
</generate-with>
-
+
+ <entry-point class="com.vaadin.tests.widgetset.client.TestingWidgetsetEntryPoint" />
</module>
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/ProfilerCompilationCanary.java b/uitest/src/com/vaadin/tests/widgetset/client/ProfilerCompilationCanary.java
new file mode 100644
index 0000000000..d5ab1da2f9
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/ProfilerCompilationCanary.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.widgetset.client;
+
+import com.google.gwt.user.client.ui.Label;
+import com.vaadin.client.Profiler;
+
+public class ProfilerCompilationCanary extends Label {
+ public ProfilerCompilationCanary() {
+ if (Profiler.isEnabled()) {
+ setText("Test does not work when profiler is enabled {dummyCode;}");
+ } else {
+ setText(getCanaryCode());
+ }
+ }
+
+ /*
+ * Finds the native js function for the canaryWithProfiler method and gets a
+ * string representation of it, which in most browsers produces the actual
+ * method implementation that we want to verify has an empty body.
+ */
+ private static native String getCanaryCode()
+ /*-{
+ return @ProfilerCompilationCanary::canaryWithProfiler(*).toString();
+ }-*/;
+
+ /*
+ * We don't care about running this method, we just want to make sure that
+ * the generated implementation is empty.
+ */
+ public static void canaryWithProfiler() {
+ Profiler.enter("canaryWithProfiler");
+ Profiler.leave("canaryWithProfiler");
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.java b/uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.java
new file mode 100644
index 0000000000..7268d02993
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.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.widgetset.client;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.client.Window.Location;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ValueMap;
+import com.vaadin.client.debug.internal.DebugButton;
+import com.vaadin.client.debug.internal.Icon;
+import com.vaadin.client.debug.internal.Section;
+import com.vaadin.client.debug.internal.VDebugWindow;
+
+public class TestingWidgetsetEntryPoint implements EntryPoint {
+
+ @Override
+ public void onModuleLoad() {
+ if (Location.getPath().contains("PreserveCustomDebugSectionOpen")) {
+ addDummyDebugWindowSection();
+ }
+ }
+
+ private void addDummyDebugWindowSection() {
+ VDebugWindow.get().addSection(new Section() {
+ private final DebugButton tabButton = new DebugButton(Icon.ERROR,
+ "Dummy debug window section");
+ private final Label controls = new Label("");
+ private final Label contents = new Label(
+ "Dummy debug window section");
+
+ @Override
+ public DebugButton getTabButton() {
+ return tabButton;
+ }
+
+ @Override
+ public Widget getControls() {
+ return controls;
+ }
+
+ @Override
+ public Widget getContent() {
+ return contents;
+ }
+
+ @Override
+ public void show() {
+ // nop
+ }
+
+ @Override
+ public void hide() {
+ // nop
+ }
+
+ @Override
+ public void meta(ApplicationConnection ac, ValueMap meta) {
+ // nop
+ }
+
+ @Override
+ public void uidl(ApplicationConnection ac, ValueMap uidl) {
+ // nop
+ }
+ });
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/MySelectionModelConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/MySelectionModelConnector.java
new file mode 100644
index 0000000000..81a9ab5bf1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/MySelectionModelConnector.java
@@ -0,0 +1,61 @@
+/*
+ * 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.widgetset.client.grid;
+
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.connectors.MultiSelectionModelConnector;
+import com.vaadin.client.renderers.ComplexRenderer;
+import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
+import com.vaadin.client.widget.grid.selection.SelectionModel.Multi;
+import com.vaadin.client.widgets.Grid;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.components.grid.GridCustomSelectionModel.MySelectionModel;
+
+import elemental.json.JsonObject;
+
+@Connect(MySelectionModel.class)
+public class MySelectionModelConnector extends MultiSelectionModelConnector {
+
+ private ClickSelectHandler<JsonObject> handler;
+
+ @Override
+ protected void extend(ServerConnector target) {
+ super.extend(target);
+ handler = new ClickSelectHandler<JsonObject>(getGrid());
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ handler.removeHandler();
+ handler = null;
+ }
+
+ @Override
+ protected Multi<JsonObject> createSelectionModel() {
+ return new MySelectionModel();
+ }
+
+ public class MySelectionModel extends MultiSelectionModel {
+
+ @Override
+ protected ComplexRenderer<Boolean> createSelectionColumnRenderer(
+ Grid<JsonObject> grid) {
+ // No Selection Column.
+ return null;
+ }
+ }
+}
diff --git a/uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html b/uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html
deleted file mode 100644
index 4828069e2a..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="http://localhost:8888/" />
-<title>New Test</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">New Test</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/OutOfSyncTest?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>pause</td>
- <td>1000</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runOutOfSyncTest::/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<!--Out of sync occured -> the button should be removed-->
-<tr>
- <td>assertElementNotPresent</td>
- <td>vaadin=runOutOfSyncTest::/VButton[0]</td>
- <td></td>
-</tr>
-
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html b/uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html
deleted file mode 100644
index 37186bd901..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="" />
-<title>EmbeddedWithNullSource</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">EmbeddedWithNullSource</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/EmbeddedWithNullSource?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td></td>
-</tr>
-
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html b/uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html
deleted file mode 100644
index ff6c82dfdb..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html
+++ /dev/null
@@ -1,152 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="" />
-<title>New Test</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">New Test</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.combobox.Comboboxes?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>select</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]</td>
- <td>label=16x16</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VFilterSelect[0]/domChild[1]</td>
- <td>13,8</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/domChild[0]/domChild[2]/domChild[0]</td>
- <td>116,6</td>
-</tr>
-<!-- Open twice to avoid IE6 css issues -->
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.combobox.Comboboxes?restartApplication</td>
- <td></td>
-</tr>
-<tr>
- <td>select</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]</td>
- <td>label=16x16</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VFilterSelect[0]/domChild[1]</td>
- <td>13,8</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>icons-16x16-page1</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/domChild[0]/domChild[2]/domChild[0]</td>
- <td>116,6</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>icons-16x16-page2</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item0</td>
- <td>378,1</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>icons-16x16-selected-1-3-5-9</td>
-</tr>
-<tr>
- <td>select</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]</td>
- <td>label=32x32</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VFilterSelect[0]/domChild[2]</td>
- <td>8,13</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>icons-32x32-page2</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td>
- <td>409,27</td>
-</tr>
-<tr>
- <td>select</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]</td>
- <td>label=64x64</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[9]/VFilterSelect[0]/domChild[1]</td>
- <td>11,13</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item1</td>
- <td>213,57</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[4]</td>
- <td>535,43</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VFilterSelect[0]/domChild[1]</td>
- <td>7,12</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item1</td>
- <td>158,25</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]</td>
- <td>16,9</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]</td>
- <td>80,7</td>
-</tr>
-<tr>
- <td>pressSpecialKey</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]</td>
- <td>down</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>icons-64x64-page1-highlight-first</td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[6]/domChild[0]</td>
- <td>510,1</td>
-</tr>
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html b/uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html
deleted file mode 100644
index 4dc63721a1..0000000000
--- a/uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="" />
-<title>ColumnCollapsingAndColumnExpansion</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">ColumnCollapsingAndColumnExpansion</td></tr>
-</thead><tbody>
-<tr>
- <td>open</td>
- <td>/run/com.vaadin.tests.components.table.ColumnCollapsingAndColumnExpansion?restartApplication</td>
- <td></td>
-</tr>
-<!--Initial state, all 3 columns visible-->
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>col1-col2-col3-visible</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[1]</td>
- <td></td>
-</tr>
-<!--Hide 'col2' through table interface-->
-<tr>
- <td>mouseClick</td>
- <td>//tr[2]/td/span/div</td>
- <td>23,2</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>col2-hidden</td>
-</tr>
-<!--Hide 'Col1' using button-->
-<tr>
- <td>enterCharacter</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]</td>
- <td>Col1</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>col1-col2-hidden</td>
-</tr>
-<!--Show 'col2' using action handler-->
-<tr>
- <td>contextmenu</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VContextMenu[0]#option0</td>
- <td>11,6</td>
-</tr>
-<tr>
- <td>enterCharacter</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]</td>
- <td>Col2</td>
-</tr>
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>col1-hidden</td>
-</tr>
-<!--Show 'Col1' using button-->
-<tr>
- <td>enterCharacter</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]</td>
- <td>Col1</td>
-</tr>
-<tr>
- <td>click</td>
- <td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
- <td></td>
-</tr>
-<!--We should now be back at the initial state, all 3 columns visible-->
-<tr>
- <td>screenCapture</td>
- <td></td>
- <td>col1-col2-col3-visible-again</td>
-</tr>
-</tbody></table>
-</body>
-</html>
diff --git a/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html b/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html
index f0f08efb58..92e2e05197 100644
--- a/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html
+++ b/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html
@@ -35,7 +35,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4</td>
<td>49,10</td>
</tr>
<tr>
@@ -60,7 +60,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4</td>
<td>49,5</td>
</tr>
<tr>
@@ -85,7 +85,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4</td>
<td>74,11</td>
</tr>
<tr>
@@ -110,7 +110,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4</td>
<td>89,4</td>
</tr>
<tr>
@@ -252,12 +252,12 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3</td>
<td>49,4</td>
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item2</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item4</td>
<td>80,12</td>
</tr>
<tr>
@@ -267,12 +267,12 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3</td>
<td>67,14</td>
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item3</td>
+ <td>vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item5</td>
<td>71,9</td>
</tr>
<!--show log to be able to assert-->