summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/demo
diff options
context:
space:
mode:
authorHenri Sara <henri.sara@itmill.com>2009-05-11 09:19:03 +0000
committerHenri Sara <henri.sara@itmill.com>2009-05-11 09:19:03 +0000
commitadc8c0ad3573272c236040c3a76005b9e73a5737 (patch)
treea3860704dbd5b82dc6af38684b80f8ef79a32722 /src/com/vaadin/demo
parent5abc870dda584d0c2fc47fd5eec4ae3de3fa240e (diff)
downloadvaadin-framework-adc8c0ad3573272c236040c3a76005b9e73a5737.tar.gz
vaadin-framework-adc8c0ad3573272c236040c3a76005b9e73a5737.zip
#2904: initial bulk rename "com.itmill.toolkit" -> "com.vaadin"
- com.itmill.toolkit.external not yet fully renamed svn changeset:7715/svn branch:6.0
Diffstat (limited to 'src/com/vaadin/demo')
-rw-r--r--src/com/vaadin/demo/Calc.java76
-rw-r--r--src/com/vaadin/demo/HelloWorld.java22
-rw-r--r--src/com/vaadin/demo/PortletDemo.java152
-rw-r--r--src/com/vaadin/demo/SimpleAddressBook.java137
-rw-r--r--src/com/vaadin/demo/ToolkitTunesLayout.java335
-rw-r--r--src/com/vaadin/demo/colorpicker/ColorPicker.java67
-rw-r--r--src/com/vaadin/demo/colorpicker/ColorPickerApplication.java55
-rw-r--r--src/com/vaadin/demo/colorpicker/gwt/ColorPickerWidgetSet.gwt.xml11
-rw-r--r--src/com/vaadin/demo/colorpicker/gwt/client/ColorPickerWidgetSet.java36
-rw-r--r--src/com/vaadin/demo/colorpicker/gwt/client/ui/GwtColorPicker.java104
-rw-r--r--src/com/vaadin/demo/colorpicker/gwt/client/ui/IColorPicker.java82
-rw-r--r--src/com/vaadin/demo/colorpicker/gwt/public/colorpicker/styles.css26
-rw-r--r--src/com/vaadin/demo/coverflow/Coverflow.java89
-rw-r--r--src/com/vaadin/demo/coverflow/CoverflowApplication.html149
-rw-r--r--src/com/vaadin/demo/coverflow/CoverflowApplication.java114
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/CoverflowWidgetSet.gwt.xml8
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/client/CoverflowWidgetSet.java34
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/client/ui/ICoverflow.java336
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/flex/Cover.as392
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/flex/Coverflow.as598
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/flex/EventHandler.as16
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/flex/coverflowflash.mxml34
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/DistortImage.as306
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/SandyPoint.as17
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/Triangle.as20
-rw-r--r--src/com/vaadin/demo/coverflow/gwt/public/coverflowflash.swfbin0 -> 176877 bytes
-rw-r--r--src/com/vaadin/demo/featurebrowser/AccordionExample.java38
-rw-r--r--src/com/vaadin/demo/featurebrowser/ButtonExample.java139
-rw-r--r--src/com/vaadin/demo/featurebrowser/ClientCachingExample.java71
-rw-r--r--src/com/vaadin/demo/featurebrowser/ComboBoxExample.java70
-rw-r--r--src/com/vaadin/demo/featurebrowser/EmbeddedBrowserExample.java90
-rw-r--r--src/com/vaadin/demo/featurebrowser/FeatureBrowser.java383
-rw-r--r--src/com/vaadin/demo/featurebrowser/FormExample.java229
-rw-r--r--src/com/vaadin/demo/featurebrowser/GeneratedColumnExample.java556
-rw-r--r--src/com/vaadin/demo/featurebrowser/JavaScriptAPIExample.java97
-rw-r--r--src/com/vaadin/demo/featurebrowser/LabelExample.java77
-rw-r--r--src/com/vaadin/demo/featurebrowser/LayoutExample.java88
-rw-r--r--src/com/vaadin/demo/featurebrowser/NotificationExample.java95
-rw-r--r--src/com/vaadin/demo/featurebrowser/RichTextExample.java63
-rw-r--r--src/com/vaadin/demo/featurebrowser/SelectExample.java102
-rw-r--r--src/com/vaadin/demo/featurebrowser/TableExample.java298
-rw-r--r--src/com/vaadin/demo/featurebrowser/TreeExample.java162
-rw-r--r--src/com/vaadin/demo/featurebrowser/ValueInputExample.java146
-rw-r--r--src/com/vaadin/demo/featurebrowser/WindowingExample.java112
-rw-r--r--src/com/vaadin/demo/package.html22
-rw-r--r--src/com/vaadin/demo/reservation/CalendarDemo.java120
-rw-r--r--src/com/vaadin/demo/reservation/CalendarField.java331
-rw-r--r--src/com/vaadin/demo/reservation/GoogleMap.java195
-rw-r--r--src/com/vaadin/demo/reservation/ReservationApplication.java335
-rw-r--r--src/com/vaadin/demo/reservation/ResourceNotAvailableException.java11
-rw-r--r--src/com/vaadin/demo/reservation/ResourceSelectorPanel.java140
-rw-r--r--src/com/vaadin/demo/reservation/SampleDB.java558
-rw-r--r--src/com/vaadin/demo/reservation/gwt/ReservationWidgetSet.gwt.xml29
-rw-r--r--src/com/vaadin/demo/reservation/gwt/client/ReservationWidgetSet.java37
-rw-r--r--src/com/vaadin/demo/reservation/gwt/client/ui/ICalendarField.java294
-rw-r--r--src/com/vaadin/demo/reservation/gwt/client/ui/IGoogleMap.java91
-rw-r--r--src/com/vaadin/demo/reservation/gwt/public/reservr/googlemap/css/googlemap.css4
-rwxr-xr-xsrc/com/vaadin/demo/reservation/gwt/public/reservr/img/calendar-time-selected.gifbin0 -> 48 bytes
-rw-r--r--src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-bg.jpgbin0 -> 357 bytes
-rw-r--r--src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-topleft.jpgbin0 -> 687 bytes
-rw-r--r--src/com/vaadin/demo/reservation/gwt/public/reservr/img/event-bg.jpgbin0 -> 437 bytes
-rw-r--r--src/com/vaadin/demo/reservation/gwt/public/reservr/styles.css149
-rw-r--r--src/com/vaadin/demo/reservation/simple/AdminView.java98
-rw-r--r--src/com/vaadin/demo/reservation/simple/SampleDB.java501
-rw-r--r--src/com/vaadin/demo/reservation/simple/SimpleReserver.java134
-rw-r--r--src/com/vaadin/demo/reservation/simple/StdView.java194
-rw-r--r--src/com/vaadin/demo/sampler/APIResource.java57
-rw-r--r--src/com/vaadin/demo/sampler/ActiveLink.java164
-rw-r--r--src/com/vaadin/demo/sampler/CodeLabel.java31
-rw-r--r--src/com/vaadin/demo/sampler/ExampleUtil.java242
-rw-r--r--src/com/vaadin/demo/sampler/Feature.java203
-rw-r--r--src/com/vaadin/demo/sampler/FeatureSet.java543
-rw-r--r--src/com/vaadin/demo/sampler/FeatureView.java258
-rw-r--r--src/com/vaadin/demo/sampler/GoogleAnalytics.java54
-rw-r--r--src/com/vaadin/demo/sampler/ModeSwitch.java106
-rw-r--r--src/com/vaadin/demo/sampler/NamedExternalResource.java18
-rw-r--r--src/com/vaadin/demo/sampler/SamplerApplication.java777
-rw-r--r--src/com/vaadin/demo/sampler/features/accordions/75-AccordionDisabled.pngbin0 -> 6137 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/accordions/75-AccordionIcons.pngbin0 -> 5941 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/accordions/AccordionDisabled.java36
-rw-r--r--src/com/vaadin/demo/sampler/features/accordions/AccordionDisabledExample.java87
-rw-r--r--src/com/vaadin/demo/sampler/features/accordions/AccordionIcons.java37
-rw-r--r--src/com/vaadin/demo/sampler/features/accordions/AccordionIconsExample.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/blueprints/75-ProminentPrimaryAction.pngbin0 -> 7433 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryAction.java55
-rw-r--r--src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryActionExample.java68
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/75-ButtonLink.pngbin0 -> 3284 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/75-ButtonPush.pngbin0 -> 5459 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/75-ButtonSwitch.pngbin0 -> 5063 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/ButtonLink.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/ButtonLinkExample.java51
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/ButtonPush.java40
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/ButtonPushExample.java48
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/ButtonSwitch.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/buttons/ButtonSwitchExample.java52
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/75-Errors.pngbin0 -> 5295 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/75-Icons.pngbin0 -> 7020 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/75-Tooltips.pngbin0 -> 12665 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/75-Validation.pngbin0 -> 6638 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/Errors.java52
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/ErrorsExample.java24
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/Icons.java55
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/IconsExample.java49
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/Tooltips.java40
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/TooltipsExample.java56
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/Validation.java46
-rw-r--r--src/com/vaadin/demo/sampler/features/commons/ValidationExample.java62
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/75-DateInline.pngbin0 -> 5854 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/75-DateLocale.pngbin0 -> 4524 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/75-DatePopup.pngbin0 -> 4802 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/75-DateResolution.pngbin0 -> 5613 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DateInline.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DateInlineExample.java40
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DateLocale.java42
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DateLocaleExample.java48
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DatePopup.java38
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DatePopupExample.java46
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DateResolution.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/dates/DateResolutionExample.java69
-rw-r--r--src/com/vaadin/demo/sampler/features/form/75-FormBasic.pngbin0 -> 4945 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/form/75-FormPojo.pngbin0 -> 8388 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/form/FormBasic.java55
-rw-r--r--src/com/vaadin/demo/sampler/features/form/FormPojo.java51
-rw-r--r--src/com/vaadin/demo/sampler/features/form/FormPojoExample.java253
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-ApplicationLayout.pngbin0 -> 3865 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-CustomLayouts.pngbin0 -> 4227 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-ExpandingComponent.pngbin0 -> 7207 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-GridLayoutBasic.pngbin0 -> 3928 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-HorizontalLayoutBasic.pngbin0 -> 2609 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-LayoutAlignment.pngbin0 -> 3633 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-LayoutMargin.pngbin0 -> 6103 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-LayoutSpacing.pngbin0 -> 9380 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-SplitPanelBasic.pngbin0 -> 10390 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-VerticalLayoutBasic.pngbin0 -> 3591 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/75-WebLayout.pngbin0 -> 4963 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/ApplicationLayout.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/ApplicationLayoutExample.java99
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/CustomLayouts.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/CustomLayoutsExample.java30
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/ExpandingComponent.java41
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/ExpandingComponentExample.java64
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasic.java40
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasicExample.java55
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasic.java35
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasicExample.java48
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/LayoutAlignment.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/LayoutAlignmentExample.java88
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/LayoutMargin.java47
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/LayoutMarginExample.java58
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/LayoutSpacing.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/LayoutSpacingExample.java38
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasic.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasicExample.java50
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasic.java37
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasicExample.java18
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/WebLayout.java44
-rw-r--r--src/com/vaadin/demo/sampler/features/layouts/WebLayoutExample.java87
-rw-r--r--src/com/vaadin/demo/sampler/features/link/75-LinkCurrentWindow.pngbin0 -> 4548 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/link/75-LinkNoDecorations.pngbin0 -> 5513 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/link/75-LinkSizedWindow.pngbin0 -> 4966 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/link/LinkCurrentWindow.java38
-rw-r--r--src/com/vaadin/demo/sampler/features/link/LinkCurrentWindowExample.java38
-rw-r--r--src/com/vaadin/demo/sampler/features/link/LinkNoDecorations.java38
-rw-r--r--src/com/vaadin/demo/sampler/features/link/LinkNoDecorationsExample.java44
-rw-r--r--src/com/vaadin/demo/sampler/features/link/LinkSizedWindow.java38
-rw-r--r--src/com/vaadin/demo/sampler/features/link/LinkSizedWindowExample.java52
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/75-NotificationCustom.pngbin0 -> 6701 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/75-NotificationError.pngbin0 -> 6333 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/75-NotificationHumanized.pngbin0 -> 6108 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/75-NotificationTray.pngbin0 -> 3692 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/75-NotificationWarning.pngbin0 -> 7110 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationCustom.java45
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationCustomExample.java133
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationError.java46
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationErrorExample.java42
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationHumanized.java48
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationHumanizedExample.java37
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationTray.java49
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationTrayExample.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationWarning.java49
-rw-r--r--src/com/vaadin/demo/sampler/features/notifications/NotificationWarningExample.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/panels/75-PanelBasic.pngbin0 -> 5204 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/panels/75-PanelLight.pngbin0 -> 4652 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/panels/PanelBasic.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/panels/PanelBasicExample.java47
-rw-r--r--src/com/vaadin/demo/sampler/features/panels/PanelLight.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/panels/PanelLightExample.java49
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-ComboBoxContains.pngbin0 -> 7912 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-ComboBoxInputPrompt.pngbin0 -> 3317 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-ComboBoxNewItems.pngbin0 -> 5573 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-ComboBoxPlain.pngbin0 -> 5120 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-ComboBoxStartsWith.pngbin0 -> 7256 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-ListSelectMultiple.pngbin0 -> 8633 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-ListSelectSingle.pngbin0 -> 8167 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-NativeSelection.pngbin0 -> 7721 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/75-TwinColumnSelect.pngbin0 -> 7415 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxContains.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxContainsExample.java50
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPrompt.java44
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPromptExample.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItems.java45
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItemsExample.java51
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxPlain.java40
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxPlainExample.java37
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWith.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWithExample.java50
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ListSelectMultiple.java41
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ListSelectMultipleExample.java37
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ListSelectSingle.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/ListSelectSingleExample.java41
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/NativeSelection.java45
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/NativeSelectionExample.java37
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/TwinColumnSelect.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/selects/TwinColumnSelectExample.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableActions.pngbin0 -> 10540 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableCellStyling.pngbin0 -> 8540 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableColumnAlignment.pngbin0 -> 7501 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableColumnCollapsing.pngbin0 -> 10964 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableColumnHeaders.pngbin0 -> 7921 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableColumnReordering.pngbin0 -> 8709 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableHeaderIcons.pngbin0 -> 7921 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableLazyLoading.pngbin0 -> 4065 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableMouseEvents.pngbin0 -> 8540 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableRowHeaders.pngbin0 -> 7921 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableRowStyling.pngbin0 -> 7103 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/75-TableSorting.pngbin0 -> 6362 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableActions.java44
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableCellStyling.java46
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableColumnAlignment.java42
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableColumnCollapsing.java46
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableColumnHeaders.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableColumnReordering.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableHeaderIcons.java44
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableLazyLoading.java46
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableMainFeaturesExample.java150
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableMouseEvents.java45
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableRowHeaders.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableRowStyling.java46
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableSorting.java45
-rw-r--r--src/com/vaadin/demo/sampler/features/table/TableStylingExample.java154
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetDisabled.pngbin0 -> 5778 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetIcons.pngbin0 -> 5678 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetScrolling.pngbin0 -> 4142 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabled.java35
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabledExample.java90
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIcons.java35
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIconsExample.java52
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrolling.java35
-rw-r--r--src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrollingExample.java60
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-LabelPlain.pngbin0 -> 5149 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-LabelPreformatted.pngbin0 -> 7128 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-LabelRich.pngbin0 -> 5867 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-RichTextEditor.pngbin0 -> 9046 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-TextArea.pngbin0 -> 5842 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-TextFieldInputPrompt.pngbin0 -> 4911 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-TextFieldSecret.pngbin0 -> 5297 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/75-TextFieldSingle.pngbin0 -> 3562 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/text/LabelPlain.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/text/LabelPlainExample.java20
-rw-r--r--src/com/vaadin/demo/sampler/features/text/LabelPreformatted.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/text/LabelPreformattedExample.java25
-rw-r--r--src/com/vaadin/demo/sampler/features/text/LabelRich.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/text/LabelRichExample.java48
-rw-r--r--src/com/vaadin/demo/sampler/features/text/RichTextEditor.java42
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextArea.java40
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextAreaExample.java49
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextFieldInputPrompt.java47
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextFieldInputPromptExample.java49
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextFieldSecret.java41
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextFieldSecretExample.java40
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextFieldSingle.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/text/TextFieldSingleExample.java31
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/75-TreeActions.pngbin0 -> 6813 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/75-TreeMouseEvents.pngbin0 -> 7032 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/75-TreeMultiSelect.pngbin0 -> 7787 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/75-TreeSingleSelect.pngbin0 -> 7120 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/TreeActions.java43
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/TreeMouseEvents.java41
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/TreeMouseEventsExample.java99
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/TreeMultiSelect.java36
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/TreeMultiSelectExample.java110
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/TreeSingleSelect.java35
-rw-r--r--src/com/vaadin/demo/sampler/features/trees/TreeSingleSelectExample.java133
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/75-NativeWindow.pngbin0 -> 9208 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/75-Subwindow.pngbin0 -> 5176 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/75-SubwindowAutoSized.pngbin0 -> 4426 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/75-SubwindowClose.pngbin0 -> 5398 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/75-SubwindowModal.pngbin0 -> 6837 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/75-SubwindowPositioned.pngbin0 -> 7467 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/75-SubwindowSized.pngbin0 -> 5116 bytes
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/NativeWindow.java45
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/NativeWindowExample.java83
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/Subwindow.java38
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSized.java39
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSizedExample.java65
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowClose.java36
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowCloseExample.java52
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowExample.java56
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowModal.java47
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowModalExample.java62
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowPositioned.java36
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowPositionedExample.java99
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowSized.java37
-rw-r--r--src/com/vaadin/demo/sampler/features/windows/SubwindowSizedExample.java64
-rw-r--r--src/com/vaadin/demo/sampler/folder.gifbin0 -> 249 bytes
-rw-r--r--src/com/vaadin/demo/sampler/gwt/SamplerWidgetSet.gwt.xml15
-rw-r--r--src/com/vaadin/demo/sampler/gwt/client/SamplerWidgetSet.java40
-rw-r--r--src/com/vaadin/demo/sampler/gwt/client/ui/IActiveLink.java89
-rw-r--r--src/com/vaadin/demo/sampler/gwt/client/ui/ICodeLabel.java29
-rw-r--r--src/com/vaadin/demo/sampler/gwt/client/ui/IGoogleAnalytics.java70
-rw-r--r--src/com/vaadin/demo/sampler/gwt/public/prettify/README.txt3
-rw-r--r--src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.css1
-rw-r--r--src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.js25
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/AddressBookApplication.java244
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/data/Person.java119
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/data/PersonContainer.java93
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/data/SearchFilter.java43
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/ui/HelpWindow.java17
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/ui/ListView.java12
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/ui/NavigationTree.java28
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/ui/PersonForm.java176
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/ui/PersonList.java45
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/ui/SearchView.java99
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/ui/SharingOptions.java39
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/validators/EmailValidator.java22
-rw-r--r--src/com/vaadin/demo/tutorial/addressbook/validators/PostalCodeValidator.java22
-rw-r--r--src/com/vaadin/demo/util/SampleCalendarDatabase.java168
-rw-r--r--src/com/vaadin/demo/util/SampleDatabase.java173
-rw-r--r--src/com/vaadin/demo/util/SampleDirectory.java73
329 files changed, 20871 insertions, 0 deletions
diff --git a/src/com/vaadin/demo/Calc.java b/src/com/vaadin/demo/Calc.java
new file mode 100644
index 0000000000..3691434375
--- /dev/null
+++ b/src/com/vaadin/demo/Calc.java
@@ -0,0 +1,76 @@
+package com.vaadin.demo;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+// Calculator is created by extending Application-class. Application is
+// deployed by adding ApplicationServlet to web.xml and this class as
+// "application" parameter to the servlet.
+public class Calc extends com.vaadin.Application {
+
+ // Calculation data model is automatically stored in the user session
+ private double current = 0.0;
+ private double stored = 0.0;
+ private char lastOperationRequested = 'C';
+
+ // User interface components
+ private final Label display = new Label("0.0");
+ private final GridLayout layout = new GridLayout(4, 5);
+
+ // Application initialization creates UI and connects it to business logic
+ @Override
+ public void init() {
+
+ // Place the layout to the browser main window
+ setMainWindow(new Window("Calculator Application", layout));
+
+ // Create and add the components to the layout
+ layout.addComponent(display, 0, 0, 3, 0);
+ for (String caption : new String[] { "7", "8", "9", "/", "4", "5", "6",
+ "*", "1", "2", "3", "-", "0", "=", "C", "+" }) {
+ Button button = new Button(caption, new Button.ClickListener() {
+ public void buttonClick(Button.ClickEvent event) {
+
+ // On button click, calculate and show the result
+ display.setValue(calculate(event.getButton()));
+ }
+ });
+ layout.addComponent(button);
+ }
+ }
+
+ // Calculator "business logic" implemented here to keep the example minimal
+ private double calculate(Button buttonClicked) {
+ char requestedOperation = buttonClicked.getCaption().charAt(0);
+ if ('0' <= requestedOperation && requestedOperation <= '9') {
+ current = current * 10
+ + Double.parseDouble("" + requestedOperation);
+ return current;
+ }
+ switch (lastOperationRequested) {
+ case '+':
+ stored += current;
+ break;
+ case '-':
+ stored -= current;
+ break;
+ case '/':
+ stored /= current;
+ break;
+ case '*':
+ stored *= current;
+ break;
+ case 'C':
+ stored = current;
+ break;
+ }
+ lastOperationRequested = requestedOperation;
+ current = 0.0;
+ if (requestedOperation == 'C') {
+ stored = 0.0;
+ }
+ return stored;
+ }
+}
diff --git a/src/com/vaadin/demo/HelloWorld.java b/src/com/vaadin/demo/HelloWorld.java
new file mode 100644
index 0000000000..36862545ea
--- /dev/null
+++ b/src/com/vaadin/demo/HelloWorld.java
@@ -0,0 +1,22 @@
+package com.vaadin.demo;
+
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+public class HelloWorld extends com.vaadin.Application {
+
+ /**
+ * Init is invoked on application load (when a user accesses the application
+ * for the first time).
+ */
+ @Override
+ public void init() {
+
+ // Main window is the primary browser window
+ final Window main = new Window("Hello window");
+ setMainWindow(main);
+
+ // "Hello world" text is added to window as a Label component
+ main.addComponent(new Label("Hello World!"));
+ }
+}
diff --git a/src/com/vaadin/demo/PortletDemo.java b/src/com/vaadin/demo/PortletDemo.java
new file mode 100644
index 0000000000..9e75e20a56
--- /dev/null
+++ b/src/com/vaadin/demo/PortletDemo.java
@@ -0,0 +1,152 @@
+/**
+ *
+ */
+package com.vaadin.demo;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.PortletMode;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletURL;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.portlet.WindowState;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.gwt.server.PortletApplicationContext;
+import com.vaadin.terminal.gwt.server.PortletApplicationContext.PortletListener;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Window.Notification;
+
+/**
+ * @author marc
+ *
+ */
+public class PortletDemo extends Application {
+
+ Window main = new Window();
+ TextField tf = new TextField("Some value");
+ Label userInfo = new Label();
+ Link portletEdit = new Link();
+ Link portletMax = new Link();
+ Link someAction = null;
+
+ public void init() {
+ main = new Window();
+ setMainWindow(main);
+
+ userInfo.setCaption("User info");
+ userInfo.setContentMode(Label.CONTENT_PREFORMATTED);
+ main.addComponent(userInfo);
+
+ tf.setEnabled(false);
+ tf.setImmediate(true);
+ main.addComponent(tf);
+
+ portletEdit.setEnabled(false);
+ main.addComponent(portletEdit);
+ portletMax.setEnabled(false);
+ main.addComponent(portletMax);
+
+ if (getContext() instanceof PortletApplicationContext) {
+ PortletApplicationContext ctx = (PortletApplicationContext) getContext();
+ ctx.addPortletListener(this, new DemoPortletListener());
+ } else {
+ getMainWindow().showNotification("Not inited via Portal!",
+ Notification.TYPE_ERROR_MESSAGE);
+ }
+
+ }
+
+ private class DemoPortletListener implements PortletListener {
+
+ public void handleActionRequest(ActionRequest request,
+ ActionResponse response) {
+
+ main.addComponent(new Label("Action received"));
+
+ }
+
+ public void handleRenderRequest(RenderRequest request,
+ RenderResponse response) {
+ // Portlet up-and-running, enable stuff
+ portletEdit.setEnabled(true);
+ portletMax.setEnabled(true);
+
+ // Editable if we're in editmode
+ tf.setEnabled((request.getPortletMode() == PortletMode.EDIT));
+
+ // Show notification about current mode and state
+ getMainWindow().showNotification(
+ "Portlet status",
+ "Mode: " + request.getPortletMode() + " State: "
+ + request.getWindowState(),
+ Notification.TYPE_WARNING_MESSAGE);
+
+ // Display current user info
+ Map uinfo = (Map) request.getAttribute(PortletRequest.USER_INFO);
+ if (uinfo != null) {
+ String s = "";
+ for (Iterator it = uinfo.keySet().iterator(); it.hasNext();) {
+ Object key = it.next();
+ Object val = uinfo.get(key);
+ s += key + ": " + val + "\n";
+ }
+ if (request.isUserInRole("administrator")) {
+ s += "(administrator)";
+ }
+ userInfo.setValue(s);
+ } else {
+ userInfo.setValue("-");
+ }
+
+ // Create Edit/Done link (actionUrl)
+ PortletURL url = response.createActionURL();
+ try {
+ url
+ .setPortletMode((request.getPortletMode() == PortletMode.VIEW ? PortletMode.EDIT
+ : PortletMode.VIEW));
+ portletEdit.setResource(new ExternalResource(url.toString()));
+ portletEdit
+ .setCaption((request.getPortletMode() == PortletMode.VIEW ? "Edit"
+ : "Done"));
+ } catch (Exception e) {
+ portletEdit.setEnabled(false);
+ }
+ // Create Maximize/Normal link (actionUrl)
+ url = response.createActionURL();
+ try {
+ url
+ .setWindowState((request.getWindowState() == WindowState.NORMAL ? WindowState.MAXIMIZED
+ : WindowState.NORMAL));
+ portletMax.setResource(new ExternalResource(url.toString()));
+ portletMax
+ .setCaption((request.getWindowState() == WindowState.NORMAL ? "Maximize"
+ : "Back to normal"));
+ } catch (Exception e) {
+ portletMax.setEnabled(false);
+ }
+
+ if (someAction == null) {
+ url = response.createActionURL();
+ try {
+ someAction = new Link("An action", new ExternalResource(url
+ .toString()));
+ main.addComponent(someAction);
+ } catch (Exception e) {
+ // Oops
+ System.err.println("Could not create someAction: " + e);
+ }
+
+ }
+
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/SimpleAddressBook.java b/src/com/vaadin/demo/SimpleAddressBook.java
new file mode 100644
index 0000000000..d9a687feff
--- /dev/null
+++ b/src/com/vaadin/demo/SimpleAddressBook.java
@@ -0,0 +1,137 @@
+package com.vaadin.demo;
+
+import com.vaadin.Application;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Form;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.SplitPanel;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SimpleAddressBook extends Application {
+
+ private static String[] fields = { "First Name", "Last Name", "Company",
+ "Mobile Phone", "Work Phone", "Home Phone", "Work Email",
+ "Home Email", "Street", "Zip", "City", "State", "Country" };
+ private static String[] visibleCols = new String[] { "Last Name", "First Name",
+ "Company" };
+
+ private Table contactList = new Table();
+ private Form contactEditor = new Form();
+ private HorizontalLayout bottomLeftCorner = new HorizontalLayout();
+ private Button contactRemovalButton;
+ private IndexedContainer addressBookData = createDummyData();
+
+ public void init() {
+ initLayout();
+ initContactAddRemoveButtons();
+ initAddressList();
+ initFilteringControls();
+ }
+
+ private void initLayout() {
+ SplitPanel splitPanel = new SplitPanel(
+ SplitPanel.ORIENTATION_HORIZONTAL);
+ setMainWindow(new Window("Address Book", splitPanel));
+ VerticalLayout left = new VerticalLayout();
+ left.setSizeFull();
+ left.addComponent(contactList);
+ contactList.setSizeFull();
+ left.setExpandRatio(contactList, 1);
+ splitPanel.addComponent(left);
+ splitPanel.addComponent(contactEditor);
+ contactEditor.setSizeFull();
+ contactEditor.getLayout().setMargin(true);
+ contactEditor.setImmediate(true);
+ bottomLeftCorner.setWidth("100%");
+ left.addComponent(bottomLeftCorner);
+ }
+
+ private void initContactAddRemoveButtons() {
+ // New item button
+ bottomLeftCorner.addComponent(new Button("+", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Object id = contactList.addItem();
+ contactList.setValue(id);
+ }
+ }));
+
+ // Remove item button
+ contactRemovalButton = new Button("-", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ contactList.removeItem(contactList.getValue());
+ contactList.select(null);
+ }
+ });
+ contactRemovalButton.setVisible(false);
+ bottomLeftCorner.addComponent(contactRemovalButton);
+ }
+
+ private String[] initAddressList() {
+ contactList.setContainerDataSource(addressBookData);
+ contactList.setVisibleColumns(visibleCols);
+ contactList.setSelectable(true);
+ contactList.setImmediate(true);
+ contactList.addListener(new Property.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ Object id = contactList.getValue();
+ contactEditor.setItemDataSource(id == null ? null : contactList
+ .getItem(id));
+ contactRemovalButton.setVisible(id != null);
+ }
+ });
+ return visibleCols;
+ }
+
+ private void initFilteringControls() {
+ for (final String pn : visibleCols) {
+ final TextField sf = new TextField();
+ bottomLeftCorner.addComponent(sf);
+ sf.setWidth("100%");
+ sf.setValue(pn);
+ sf.setImmediate(true);
+ bottomLeftCorner.setExpandRatio(sf, 1);
+ sf.addListener(new Property.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ addressBookData.removeContainerFilters(pn);
+ if (sf.toString().length() > 0 && !pn.equals(sf.toString()))
+ addressBookData.addContainerFilter(pn, sf.toString(),
+ true, false);
+ getMainWindow().showNotification(
+ "" + addressBookData.size() + " matches found");
+ }
+ });
+ }
+ }
+ private static IndexedContainer createDummyData() {
+
+ String[] fnames = { "Peter", "Alice", "Joshua", "Mike", "Olivia",
+ "Nina", "Alex", "Rita", "Dan", "Umberto", "Henrik", "Rene",
+ "Lisa", "Marge" };
+ String[] lnames = { "Smith", "Gordon", "Simpson", "Brown", "Clavel",
+ "Simons", "Verne", "Scott", "Allison", "Gates", "Rowling",
+ "Barks", "Ross", "Schneider", "Tate" };
+
+ IndexedContainer ic = new IndexedContainer();
+
+ for (String p : fields)
+ ic.addContainerProperty(p, String.class, "");
+
+ for (int i = 0; i < 1000; i++) {
+ Object id = ic.addItem();
+ ic.getContainerProperty(id, "First Name").setValue(
+ fnames[(int) (fnames.length * Math.random())]);
+ ic.getContainerProperty(id, "Last Name").setValue(
+ lnames[(int) (lnames.length * Math.random())]);
+ }
+
+ return ic;
+ }
+
+}
diff --git a/src/com/vaadin/demo/ToolkitTunesLayout.java b/src/com/vaadin/demo/ToolkitTunesLayout.java
new file mode 100644
index 0000000000..4951eb2105
--- /dev/null
+++ b/src/com/vaadin/demo/ToolkitTunesLayout.java
@@ -0,0 +1,335 @@
+package com.vaadin.demo;
+
+import java.util.Random;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.Slider;
+import com.vaadin.ui.SplitPanel;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Window.Notification;
+
+/**
+ * Sample application layout, similar (almost identical) to Apple iTunes.
+ *
+ * @author IT Mill Ltd.
+ *
+ */
+@SuppressWarnings("serial")
+public class ToolkitTunesLayout extends Application {
+
+ @Override
+ public void init() {
+
+ /*
+ * We'll build the whole UI here, since the application will not contain
+ * any logic. Otherwise it would be more practical to separate parts of
+ * the UI into different classes and methods.
+ */
+
+ // Main (browser) window, needed in all Toolkit applications
+ final Window root = new Window("ToolkitTunes");
+
+ /*
+ * We'll attach the window to the browser view already here, so we won't
+ * forget it later.
+ */
+ setMainWindow(root);
+
+ root
+ .showNotification(
+ "This is an example of how you can do layouts in IT Mill Toolkit.<br/>It is not a working sound player.",
+ Notification.TYPE_HUMANIZED_MESSAGE);
+
+ // Our root window contains one VerticalLayout by default, let's make
+ // sure it's 100% sized, and remove unwanted margins
+ root.getLayout().setSizeFull();
+ root.getLayout().setMargin(false);
+
+ // Top area, containing playback and volume controls, play status, view
+ // modes and search
+ HorizontalLayout top = new HorizontalLayout();
+ top.setWidth("100%");
+ top.setMargin(false, true, false, true); // Enable horizontal margins
+ top.setSpacing(true);
+
+ // Let's attach that one straight away too
+ root.addComponent(top);
+
+ // Create the placeholders for all the components in the top area
+ HorizontalLayout playback = new HorizontalLayout();
+ HorizontalLayout volume = new HorizontalLayout();
+ HorizontalLayout status = new HorizontalLayout();
+ HorizontalLayout viewmodes = new HorizontalLayout();
+ ComboBox search = new ComboBox();
+
+ // Add the components and align them properly
+ top.addComponent(playback);
+ top.addComponent(volume);
+ top.addComponent(status);
+ top.addComponent(viewmodes);
+ top.addComponent(search);
+ top.setComponentAlignment(playback, "middle");
+ top.setComponentAlignment(volume, "middle");
+ top.setComponentAlignment(status, "middle center");
+ top.setComponentAlignment(viewmodes, "middle");
+ top.setComponentAlignment(search, "middle");
+
+ /*
+ * We want our status area to expand if the user resizes the root
+ * window, and we want it to accommodate as much space as there is
+ * available. All other components in the top layout should stay fixed
+ * sized, so we don't need to specify any expand ratios for them (they
+ * will automatically revert to zero after the following line).
+ */
+ top.setExpandRatio(status, 1.0F);
+
+ // Playback controls
+ Button prev = new Button("Previous");
+ Button play = new Button("Play/pause");
+ Button next = new Button("Next");
+ playback.addComponent(prev);
+ playback.addComponent(play);
+ playback.addComponent(next);
+ // Set spacing between the buttons
+ playback.setSpacing(true);
+
+ // Volume controls
+ Button mute = new Button("mute");
+ Slider vol = new Slider();
+ vol.setOrientation(Slider.ORIENTATION_HORIZONTAL);
+ vol.setWidth("100px");
+ Button max = new Button("max");
+ volume.addComponent(mute);
+ volume.addComponent(vol);
+ volume.addComponent(max);
+
+ // Status area
+ status.setWidth("80%");
+ status.setSpacing(true);
+
+ Button toggleVisualization = new Button("Mode");
+ Label timeFromStart = new Label("0:00");
+
+ // We'll need another layout to show currently playing track and
+ // progress
+ VerticalLayout trackDetails = new VerticalLayout();
+ trackDetails.setWidth("100%");
+ Label track = new Label("Track Name");
+ Label album = new Label("Album Name - Artist");
+ track.setWidth(null);
+ album.setWidth(null);
+ Slider progress = new Slider();
+ progress.setOrientation(Slider.ORIENTATION_HORIZONTAL);
+ progress.setWidth("100%");
+ trackDetails.addComponent(track);
+ trackDetails.addComponent(album);
+ trackDetails.addComponent(progress);
+ trackDetails.setComponentAlignment(track, "center");
+ trackDetails.setComponentAlignment(album, "center");
+
+ Label timeToEnd = new Label("-4:46");
+ Button jumpToTrack = new Button("Show");
+
+ // Place all components to the status layout and align them properly
+ status.addComponent(toggleVisualization);
+ status.setComponentAlignment(toggleVisualization, "middle");
+ status.addComponent(timeFromStart);
+ status.setComponentAlignment(timeFromStart, "bottom");
+ status.addComponent(trackDetails);
+ status.addComponent(timeToEnd);
+ status.setComponentAlignment(timeToEnd, "bottom");
+ status.addComponent(jumpToTrack);
+ status.setComponentAlignment(jumpToTrack, "middle");
+
+ // Then remember to specify the expand ratio
+ status.setExpandRatio(trackDetails, 1.0F);
+
+ // View mode buttons
+ Button viewAsTable = new Button("Table");
+ Button viewAsGrid = new Button("Grid");
+ Button coverflow = new Button("Coverflow");
+ viewmodes.addComponent(viewAsTable);
+ viewmodes.addComponent(viewAsGrid);
+ viewmodes.addComponent(coverflow);
+
+ /*
+ * That covers the top bar. Now let's move on to the sidebar and track
+ * listing
+ */
+
+ // We'll need one splitpanel to separate the sidebar and track listing
+ SplitPanel bottom = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL);
+ root.addComponent(bottom);
+
+ // The splitpanel is by default 100% x 100%, but we'll need to adjust
+ // our main window layout to accomodate the height
+ ((VerticalLayout) root.getLayout()).setExpandRatio(bottom, 1.0F);
+
+ // Give the sidebar less space than the listing
+ bottom.setSplitPosition(200, SplitPanel.UNITS_PIXELS);
+
+ // Let's add some content to the sidebar
+ // First, we need a layout to but all components in
+ VerticalLayout sidebar = new VerticalLayout();
+ sidebar.setSizeFull();
+ bottom.setFirstComponent(sidebar);
+
+ /*
+ * Then we need some labels and buttons, and an album cover image The
+ * labels and buttons go into their own vertical layout, since we want
+ * the 'sidebar' layout to be expanding (cover image in the bottom).
+ * VerticalLayout is by default 100% wide.
+ */
+ VerticalLayout selections = new VerticalLayout();
+ Label library = new Label("Library");
+ Button music = new Button("Music");
+ music.setWidth("100%");
+
+ Label store = new Label("Store");
+ Button toolkitTunesStore = new Button("ToolkitTunes Store");
+ toolkitTunesStore.setWidth("100%");
+ Button purchased = new Button("Purchased");
+ purchased.setWidth("100%");
+
+ Label playlists = new Label("Playlists");
+ Button genius = new Button("Geniues");
+ genius.setWidth("100%");
+ Button recent = new Button("Recently Added");
+ recent.setWidth("100%");
+
+ // Lets add them to the 'selections' layout
+ selections.addComponent(library);
+ selections.addComponent(music);
+ selections.addComponent(store);
+ selections.addComponent(toolkitTunesStore);
+ selections.addComponent(purchased);
+ selections.addComponent(playlists);
+ selections.addComponent(genius);
+ selections.addComponent(recent);
+
+ // Then add the selections to the sidebar, and set it expanding
+ sidebar.addComponent(selections);
+ sidebar.setExpandRatio(selections, 1.0F);
+
+ // Then comes the cover artwork (we'll add the actual image in the
+ // themeing section)
+ Embedded cover = new Embedded("Currently Playing");
+ sidebar.addComponent(cover);
+
+ /*
+ * And lastly, we need the track listing table It should fill the whole
+ * left side of our bottom layout
+ */
+ Table listing = new Table();
+ listing.setSizeFull();
+ listing.setSelectable(true);
+ bottom.setSecondComponent(listing);
+
+ // Add the table headers
+ listing.addContainerProperty("Name", String.class, "");
+ listing.addContainerProperty("Time", String.class, "0:00");
+ listing.addContainerProperty("Artist", String.class, "");
+ listing.addContainerProperty("Album", String.class, "");
+ listing.addContainerProperty("Genre", String.class, "");
+ listing.addContainerProperty("Rating", NativeSelect.class,
+ new NativeSelect());
+
+ // Lets populate the table with random data
+ String[] tracks = new String[] { "Red Flag", "Millstone",
+ "Not The Sun", "Breath", "Here We Are", "Deep Heaven",
+ "Her Voice Resides", "Natural Tan", "End It All", "Kings",
+ "Daylight Slaving", "Mad Man", "Resolve", "Teargas",
+ "African Air", "Passing Bird" };
+ String[] times = new String[] { "4:12", "6:03", "5:43", "4:32", "3:42",
+ "4:45", "2:56", "9:34", "2:10", "3:44", "5:49", "6:30", "5:18",
+ "7:42", "3:13", "2:52" };
+ String[] artists = new String[] { "Billy Talent", "Brand New",
+ "Breaking Benjamin", "Becoming The Archetype",
+ "Bullet For My Valentine", "Chasing Victory", "Chimaira",
+ "Danko Jones", "Deadlock", "Deftones", "From Autumn To Ashes",
+ "Haste The Day", "Four Year Strong", "In Flames", "Kemopetrol",
+ "John Legend" };
+ String[] albums = new String[] { "Once Again", "The Caitiff Choir",
+ "The Devil And God", "Light Grenades", "Dicthonomy",
+ "Back In Black", "Dreamer", "Come Clarity", "Year Zero",
+ "Frames", "Fortress", "Phobia", "The Poison", "Manifesto",
+ "White Pony", "The Big Dirty" };
+ String[] genres = new String[] { "Rock", "Metal", "Hardcore", "Indie",
+ "Pop", "Alternative", "Blues", "Jazz", "Hip Hop", "Electronica" };
+ for (int i = 0; i < 1000; i++) {
+ NativeSelect s = new NativeSelect();
+ s.addItem("1 star");
+ s.addItem("2 stars");
+ s.addItem("3 stars");
+ s.addItem("4 stars");
+ s.addItem("5 stars");
+ s.select(new Random().nextInt(5) + " stars");
+ listing.addItem(new Object[] {
+ tracks[new Random().nextInt(tracks.length - 1)],
+ times[new Random().nextInt(times.length - 1)],
+ artists[new Random().nextInt(artists.length - 1)],
+ albums[new Random().nextInt(albums.length - 1)],
+ genres[new Random().nextInt(genres.length - 1)], s }, i);
+ }
+
+ // We'll align the track time column to right as well
+ listing.setColumnAlignment("Time", Table.ALIGN_RIGHT);
+
+ // TODO the footer
+
+ // Now what's left to do? Themeing of course.
+ setTheme("toolkittunes");
+
+ /*
+ * Let's give a namespace to our application window. This way, if
+ * someone uses the same theme for different applications, we don't get
+ * unwanted style conflicts.
+ */
+ root.setStyleName("tTunes");
+
+ top.setStyleName("top");
+ top.setHeight("75px"); // Same as the background image height
+
+ playback.setStyleName("playback");
+ playback.setMargin(false, true, false, false); // Add right-side margin
+ play.setStyleName("play");
+ next.setStyleName("next");
+ prev.setStyleName("prev");
+ playback.setComponentAlignment(prev, "middle");
+ playback.setComponentAlignment(next, "middle");
+
+ volume.setStyleName("volume");
+ mute.setStyleName("mute");
+ max.setStyleName("max");
+ vol.setWidth("78px");
+
+ status.setStyleName("status");
+ status.setMargin(true);
+ status.setHeight("46px"); // Height of the background image
+
+ toggleVisualization.setStyleName("toggle-vis");
+ jumpToTrack.setStyleName("jump");
+
+ viewAsTable.setStyleName("viewmode-table");
+ viewAsGrid.setStyleName("viewmode-grid");
+ coverflow.setStyleName("viewmode-coverflow");
+
+ sidebar.setStyleName("sidebar");
+
+ music.setStyleName("selected");
+
+ cover.setSource(new ThemeResource("images/album-cover.jpg"));
+ // Because this is an image, it will retain it's aspect ratio
+ cover.setWidth("100%");
+ }
+
+}
diff --git a/src/com/vaadin/demo/colorpicker/ColorPicker.java b/src/com/vaadin/demo/colorpicker/ColorPicker.java
new file mode 100644
index 0000000000..60f2807f1f
--- /dev/null
+++ b/src/com/vaadin/demo/colorpicker/ColorPicker.java
@@ -0,0 +1,67 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.colorpicker;
+
+import java.util.Map;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.AbstractField;
+
+public class ColorPicker extends AbstractField {
+
+ public ColorPicker() {
+ super();
+ setValue(new String("white"));
+ }
+
+ /** The property value of the field is an Integer. */
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ /** Tag is the UIDL element name for client-server communications. */
+ @Override
+ public String getTag() {
+ return "colorpicker";
+ }
+
+ /** Set the currently selected color. */
+ public void setColor(String newcolor) {
+ // Sets the color name as the property of the component.
+ // Setting the property will automatically cause repainting of
+ // the component with paintContent().
+ setValue(newcolor);
+ }
+
+ /** Retrieve the currently selected color. */
+ public String getColor() {
+ return (String) getValue();
+ }
+
+ /** Paint (serialize) the component for the client. */
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ // Superclass writes any common attributes in the paint target.
+ super.paintContent(target);
+
+ // Add the currently selected color as a variable in the paint
+ // target.
+ target.addVariable(this, "colorname", getColor());
+ }
+
+ /** Deserialize changes received from client. */
+ @Override
+ public void changeVariables(Object source, Map variables) {
+ // Sets the currently selected color
+ if (variables.containsKey("colorname") && !isReadOnly()) {
+ final String newValue = (String) variables.get("colorname");
+ // Changing the property of the component will
+ // trigger a ValueChangeEvent
+ setValue(newValue, true);
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/colorpicker/ColorPickerApplication.java b/src/com/vaadin/demo/colorpicker/ColorPickerApplication.java
new file mode 100644
index 0000000000..a5df17607d
--- /dev/null
+++ b/src/com/vaadin/demo/colorpicker/ColorPickerApplication.java
@@ -0,0 +1,55 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.colorpicker;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * Demonstration application that shows how to use a simple custom client-side
+ * GWT component, the ColorPicker.
+ */
+public class ColorPickerApplication extends com.vaadin.Application {
+ Window main = new Window("Color Picker Demo");
+
+ /* The custom component. */
+ ColorPicker colorselector = new ColorPicker();
+
+ /* Another component. */
+ Label colorname;
+
+ @Override
+ public void init() {
+ setMainWindow(main);
+
+ // Listen for value change events in the custom component,
+ // triggered when user clicks a button to select another color.
+ colorselector.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // Provide some server-side feedback
+ colorname.setValue("Selected color: "
+ + colorselector.getColor());
+ }
+ });
+ main.addComponent(colorselector);
+
+ // Add another component to give feedback from server-side code
+ colorname = new Label("Selected color: " + colorselector.getColor());
+ main.addComponent(colorname);
+
+ // Server-side manipulation of the component state
+ final Button button = new Button("Set to white");
+ button.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ colorselector.setColor("white");
+ }
+ });
+ main.addComponent(button);
+ }
+}
diff --git a/src/com/vaadin/demo/colorpicker/gwt/ColorPickerWidgetSet.gwt.xml b/src/com/vaadin/demo/colorpicker/gwt/ColorPickerWidgetSet.gwt.xml
new file mode 100644
index 0000000000..718ab9e2c6
--- /dev/null
+++ b/src/com/vaadin/demo/colorpicker/gwt/ColorPickerWidgetSet.gwt.xml
@@ -0,0 +1,11 @@
+<module>
+ <!-- Inherit DefaultWidgetSet -->
+ <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" />
+
+ <!-- WidgetSet default theme -->
+ <stylesheet src="colorpicker/styles.css"/>
+
+ <!-- Entry point -->
+ <entry-point class="com.vaadin.demo.colorpicker.gwt.client.ColorPickerWidgetSet"/>
+
+</module>
diff --git a/src/com/vaadin/demo/colorpicker/gwt/client/ColorPickerWidgetSet.java b/src/com/vaadin/demo/colorpicker/gwt/client/ColorPickerWidgetSet.java
new file mode 100644
index 0000000000..0a73b6eb5a
--- /dev/null
+++ b/src/com/vaadin/demo/colorpicker/gwt/client/ColorPickerWidgetSet.java
@@ -0,0 +1,36 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.colorpicker.gwt.client;
+
+import com.vaadin.demo.colorpicker.gwt.client.ui.IColorPicker;
+import com.vaadin.terminal.gwt.client.DefaultWidgetSet;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class ColorPickerWidgetSet extends DefaultWidgetSet {
+ /** Resolves UIDL tag name to widget class. */
+ @Override
+ protected Class resolveWidgetType(UIDL uidl) {
+ final String tag = uidl.getTag();
+ if ("colorpicker".equals(tag)) {
+ return IColorPicker.class;
+ }
+
+ // Let the DefaultWidgetSet handle resolution of default widgets
+ return super.resolveWidgetType(uidl);
+ }
+
+ /** Creates a widget instance according to its class object. */
+ @Override
+ public Paintable createWidget(UIDL uidl) {
+ final Class type = resolveWidgetType(uidl);
+ if (IColorPicker.class == type) {
+ return new IColorPicker();
+ }
+
+ // Let the DefaultWidgetSet handle creation of default widgets
+ return super.createWidget(uidl);
+ }
+}
diff --git a/src/com/vaadin/demo/colorpicker/gwt/client/ui/GwtColorPicker.java b/src/com/vaadin/demo/colorpicker/gwt/client/ui/GwtColorPicker.java
new file mode 100644
index 0000000000..c9bbedbd66
--- /dev/null
+++ b/src/com/vaadin/demo/colorpicker/gwt/client/ui/GwtColorPicker.java
@@ -0,0 +1,104 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.colorpicker.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * A regular GWT component without integration with IT Mill Toolkit.
+ */
+public class GwtColorPicker extends Composite implements ClickListener {
+
+ /** Currently selected color name to give client-side feedback to the user. */
+ protected Label currentcolor = new Label();
+
+ public GwtColorPicker() {
+ // Create a 4x4 grid of buttons with names for 16 colors
+ final Grid grid = new Grid(4, 4);
+ final String[] colors = new String[] { "aqua", "black", "blue",
+ "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive",
+ "purple", "red", "silver", "teal", "white", "yellow" };
+ int colornum = 0;
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++, colornum++) {
+ // Create a button for each color
+ final Button button = new Button(colors[colornum]);
+ button.addClickListener(this);
+
+ // Put the button in the Grid layout
+ grid.setWidget(i, j, button);
+
+ // Set the button background colors.
+ DOM.setStyleAttribute(button.getElement(), "background",
+ colors[colornum]);
+
+ // For dark colors, the button label must be in white.
+ if ("black navy maroon blue purple".indexOf(colors[colornum]) != -1) {
+ DOM
+ .setStyleAttribute(button.getElement(), "color",
+ "white");
+ }
+ }
+ }
+
+ // Create a panel with the color grid and currently selected color
+ // indicator
+ final HorizontalPanel panel = new HorizontalPanel();
+ panel.add(grid);
+ panel.add(currentcolor);
+
+ // Set the class of the color selection feedback box to allow CSS
+ // styling.
+ // We need to obtain the DOM element for the current color label.
+ // This assumes that the <td> element of the HorizontalPanel is
+ // the parent of the label element. Notice that the element has no
+ // parent
+ // before the widget has been added to the horizontal panel.
+ final Element panelcell = DOM.getParent(currentcolor.getElement());
+ DOM.setElementProperty(panelcell, "className",
+ "colorpicker-currentcolorbox");
+
+ // Set initial color. This will be overridden with the value read from
+ // server.
+ setColor("white");
+
+ // Composite GWT widgets must call initWidget().
+ initWidget(panel);
+ }
+
+ /** Handles click on a color button. */
+ public void onClick(Widget sender) {
+ // Use the button label as the color name to set
+ setColor(((Button) sender).getText());
+ }
+
+ /** Sets the currently selected color. */
+ public void setColor(String newcolor) {
+ // Give client-side feedback by changing the color name in the label
+ currentcolor.setText(newcolor);
+
+ // Obtain the DOM elements. This assumes that the <td> element
+ // of the HorizontalPanel is the parent of the label element.
+ final Element nameelement = currentcolor.getElement();
+ final Element cell = DOM.getParent(nameelement);
+
+ // Give feedback by changing the background color
+ DOM.setStyleAttribute(cell, "background", newcolor);
+ DOM.setStyleAttribute(nameelement, "background", newcolor);
+ if ("black navy maroon blue purple".indexOf(newcolor) != -1) {
+ DOM.setStyleAttribute(nameelement, "color", "white");
+ } else {
+ DOM.setStyleAttribute(nameelement, "color", "black");
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/colorpicker/gwt/client/ui/IColorPicker.java b/src/com/vaadin/demo/colorpicker/gwt/client/ui/IColorPicker.java
new file mode 100644
index 0000000000..f238e9dc3f
--- /dev/null
+++ b/src/com/vaadin/demo/colorpicker/gwt/client/ui/IColorPicker.java
@@ -0,0 +1,82 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.colorpicker.gwt.client.ui;
+
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class IColorPicker extends GwtColorPicker implements Paintable {
+
+ /** Set the CSS class name to allow styling. */
+ public static final String CLASSNAME = "example-colorpicker";
+
+ /** Component identifier in UIDL communications. */
+ String uidlId;
+
+ /** Reference to the server connection object. */
+ ApplicationConnection client;
+
+ /**
+ * The constructor should first call super() to initialize the component and
+ * then handle any initialization relevant to IT Mill Toolkit.
+ */
+ public IColorPicker() {
+ // The superclass has a lot of relevant initialization
+ super();
+
+ // This method call of the Paintable interface sets the component
+ // style name in DOM tree
+ setStyleName(CLASSNAME);
+ }
+
+ /**
+ * This method must be implemented to update the client-side component from
+ * UIDL data received from server.
+ *
+ * This method is called when the page is loaded for the first time, and
+ * every time UI changes in the component are received from the server.
+ */
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // This call should be made first. Ensure correct implementation,
+ // and let the containing layout manage caption, etc.
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ // Save reference to server connection object to be able to send
+ // user interaction later
+ this.client = client;
+
+ // Save the UIDL identifier for the component
+ uidlId = uidl.getId();
+
+ // Get value received from server and actualize it in the GWT component
+ setColor(uidl.getStringVariable("colorname"));
+ }
+
+ /** Override the method to communicate the new value to server. */
+ @Override
+ public void setColor(String newcolor) {
+ // Ignore if no change
+ if (newcolor.equals(currentcolor.getText())) {
+ return;
+ }
+
+ // Let the original implementation to do whatever it needs to do
+ super.setColor(newcolor);
+
+ // Updating the state to the server can not be done before
+ // the server connection is known, i.e., before updateFromUIDL()
+ // has been called.
+ if (uidlId == null || client == null) {
+ return;
+ }
+
+ // Communicate the user interaction parameters to server. This call will
+ // initiate an AJAX request to the server.
+ client.updateVariable(uidlId, "colorname", newcolor, true);
+ }
+}
diff --git a/src/com/vaadin/demo/colorpicker/gwt/public/colorpicker/styles.css b/src/com/vaadin/demo/colorpicker/gwt/public/colorpicker/styles.css
new file mode 100644
index 0000000000..4c3455ae53
--- /dev/null
+++ b/src/com/vaadin/demo/colorpicker/gwt/public/colorpicker/styles.css
@@ -0,0 +1,26 @@
+/* Set style for the color picker table.
+ This assumes that the Grid layout is rendered as a HTML <table>.*/
+table.example-colorpicker {
+ border-collapse: collapse;
+ border: 0px;
+}
+
+/* Set color picker button style.
+ This does not make assumptions about the HTML element tree as it only uses
+ the logical class names.*/
+.example-colorpicker .gwt-Button {
+ height: 60px;
+ width: 60px;
+ border: none;
+ padding: 0px;
+}
+
+/* Set style for the right-hand box that shows the currently selected color.
+ While this may work for other implementations of the HorizontalPanel as well,
+ it somewhat assumes that the layout is rendered as a table where cells
+ are <td> elements. */
+.colorpicker-currentcolorbox {
+ width: 240px;
+ text-align: center;
+ vertical-align: middle !important;
+}
diff --git a/src/com/vaadin/demo/coverflow/Coverflow.java b/src/com/vaadin/demo/coverflow/Coverflow.java
new file mode 100644
index 0000000000..5c8e9403c2
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/Coverflow.java
@@ -0,0 +1,89 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.coverflow;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.AbstractSelect;
+
+public class Coverflow extends AbstractSelect {
+
+ private String backgroundGradientStart = "FFFFFF";
+ private String backgroundGradientEnd = "EEEEEE";
+ private boolean scrollbarVisibility = true;
+
+ public String getTag() {
+ return "cover";
+ }
+
+ /**
+ * Paints the uidl
+ * @param PaintTarget target
+ * @throws PaintException
+ */
+ public void paintContent(PaintTarget target) throws PaintException {
+ // Superclass writes any common attributes in the paint target.
+ super.paintContent(target);
+
+ target.addAttribute("backgroundGradientStart", backgroundGradientStart);
+ target.addAttribute("backgroundGradientEnd", backgroundGradientEnd);
+ target.addAttribute("scrollbarVisibility", scrollbarVisibility);
+ }
+
+ /**
+ * The user can specify a background gradient for the coverflow. The input values
+ * are RGB values for the start and end gradients.
+ * @param int startR
+ * @param int startG
+ * @param int startB
+ * @param int endR
+ * @param int endG
+ * @param int endB
+ */
+ public void setBackgroundColor(int startR, int startG, int startB, int endR, int endG, int endB) {
+ backgroundGradientStart = "";
+ backgroundGradientEnd = "";
+
+ // Convert all integers to hexadecimal format and make sure they are two characters long (in
+ // other words, add a zero infront if the value is less than 16 => 0x0F
+ if(startR < 16)
+ backgroundGradientStart += "0";
+ backgroundGradientStart += Integer.toHexString(Math.max(Math.min(startR,255),0));
+
+ if(startG < 16)
+ backgroundGradientStart += "0";
+ backgroundGradientStart += Integer.toHexString(Math.max(Math.min(startG,255),0));
+
+ if(startB < 16)
+ backgroundGradientStart += "0";
+ backgroundGradientStart += Integer.toHexString(Math.max(Math.min(startB,255),0));
+
+ if(endR < 16)
+ backgroundGradientEnd += "0";
+ backgroundGradientEnd += Integer.toHexString(Math.max(Math.min(endR,255),0));
+
+ if(endG < 16)
+ backgroundGradientEnd += "0";
+ backgroundGradientEnd += Integer.toHexString(Math.max(Math.min(endG,255),0));
+
+ if(endB < 16)
+ backgroundGradientEnd += "0";
+ backgroundGradientEnd += Integer.toHexString(Math.max(Math.min(endB,255),0));
+
+ this.requestRepaint();
+ }
+
+ /**
+ * The user can toggle the visibility of the scrollbar
+ * @param boolean visible
+ */
+ public void setScrollbarVisibility(boolean visible) {
+ if(scrollbarVisibility != visible) {
+ scrollbarVisibility = visible;
+ this.requestRepaint();
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/coverflow/CoverflowApplication.html b/src/com/vaadin/demo/coverflow/CoverflowApplication.html
new file mode 100644
index 0000000000..1149357aa5
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/CoverflowApplication.html
@@ -0,0 +1,149 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head>
+<title></title>
+ <style type="text/css">
+ <!--code { font-family: Courier New, Courier; font-size: 10pt; margin: 0px; }-->
+ </style>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+</head><body>
+
+
+<!-- ======================================================== -->
+<!-- = Java Sourcecode to HTML automatically converted code = -->
+<!-- = Java2Html Converter 5.0 [2006-02-26] by Markus Gebhard markus@jave.de = -->
+<!-- = Further information: http://www.java2html.de = -->
+<div align="left" class="java">
+<table border="0" cellpadding="3" cellspacing="0" bgcolor="#ffffff">
+ <tr>
+ <!-- start source code -->
+ <td nowrap="nowrap" valign="top" align="left">
+ <code>
+<font color="#7f0055"><b>package&nbsp;</b></font><font color="#000000">com.vaadin.demo.coverflow;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.BufferedReader;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.FileInputStream;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.FileReader;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.IOException;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.InputStream;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.InputStreamReader;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.Reader;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.io.StringReader;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.net.URL;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.nio.CharBuffer;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.data.Property;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.terminal.Resource;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.terminal.Sizeable;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.terminal.ThemeResource;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.ui.Button;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.ui.Embedded;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.ui.ExpandLayout;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.ui.Label;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.ui.Window;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.ui.Button.ClickEvent;</font><br />
+<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">com.vaadin.ui.Layout.AlignmentHandler;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#7f0055"><b>public&nbsp;class&nbsp;</b></font><font color="#000000">CoverflowApplication&nbsp;</font><font color="#7f0055"><b>extends&nbsp;</b></font><font color="#000000">com.vaadin.Application&nbsp;</font><font color="#000000">{</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#000000">Coverflow&nbsp;covers&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Coverflow</font><font color="#000000">()</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font><font color="#000000">init</font><font color="#000000">()&nbsp;{</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">setMainWindow</font><font color="#000000">(</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Window</font><font color="#000000">(</font><font color="#2a00ff">&#34;Coverflow&#34;</font><font color="#000000">,&nbsp;createMainLayout</font><font color="#000000">()))</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">setTheme</font><font color="#000000">(</font><font color="#2a00ff">&#34;black&#34;</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">addSlidesToCoverflow</font><font color="#000000">()</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#7f0055"><b>private&nbsp;</b></font><font color="#000000">ExpandLayout&nbsp;createMainLayout</font><font color="#000000">()&nbsp;{</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#3f7f5f">//&nbsp;Initialize&nbsp;coverflow&nbsp;component</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">covers.setHeight</font><font color="#000000">(</font><font color="#990000">150</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">covers.setWidth</font><font color="#000000">(</font><font color="#990000">100</font><font color="#000000">,&nbsp;Sizeable.UNITS_PERCENTAGE</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">covers.setBackgroundColor</font><font color="#000000">(</font><font color="#990000">0</font><font color="#000000">,&nbsp;</font><font color="#990000">0</font><font color="#000000">,&nbsp;</font><font color="#990000">0</font><font color="#000000">,&nbsp;</font><font color="#990000">100</font><font color="#000000">,&nbsp;</font><font color="#990000">100</font><font color="#000000">,&nbsp;</font><font color="#990000">100</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#3f7f5f">//&nbsp;Initialize&nbsp;visible&nbsp;slide&nbsp;viewer</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>final&nbsp;</b></font><font color="#000000">Embedded&nbsp;visibleSlide&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Embedded</font><font color="#000000">()</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">visibleSlide.setHeight</font><font color="#000000">(</font><font color="#990000">100</font><font color="#000000">,&nbsp;Sizeable.UNITS_PERCENTAGE</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#3f7f5f">//&nbsp;Listen&nbsp;to&nbsp;coverflow&nbsp;changes&nbsp;as&nbsp;change&nbsp;slides&nbsp;when&nbsp;needed</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">covers.addListener</font><font color="#000000">(</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Property.ValueChangeListener</font><font color="#000000">()&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font><font color="#000000">valueChange</font><font color="#000000">(</font><font color="#000000">Property.ValueChangeEvent&nbsp;event</font><font color="#000000">)&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">visibleSlide.setSource</font><font color="#000000">((</font><font color="#000000">Resource</font><font color="#000000">)&nbsp;</font><font color="#000000">covers.getValue</font><font color="#000000">())</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">})</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#3f7f5f">//&nbsp;Show&nbsp;sources&nbsp;button</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">Button&nbsp;showSrc&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Button</font><font color="#000000">(</font><font color="#2a00ff">&#34;src&#34;</font><font color="#000000">,&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Button.ClickListener</font><font color="#000000">()&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font><font color="#000000">buttonClick</font><font color="#000000">(</font><font color="#000000">ClickEvent&nbsp;event</font><font color="#000000">)&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">Window&nbsp;srcWindow&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Window</font><font color="#000000">(</font><font color="#2a00ff">&#34;Source&nbsp;code&#34;</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">srcWindow.setWidth</font><font color="#000000">(</font><font color="#990000">700</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">srcWindow.setHeight</font><font color="#000000">(</font><font color="#990000">500</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">Label&nbsp;l&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">Label</font><font color="#000000">(</font><font color="#000000">getSourceCodeForThisClass</font><font color="#000000">()</font><font color="#000000">,</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">Label.CONTENT_XHTML</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">srcWindow.addComponent</font><font color="#000000">(</font><font color="#000000">l</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">getMainWindow</font><font color="#000000">()</font><font color="#000000">.addWindow</font><font color="#000000">(</font><font color="#000000">srcWindow</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">})</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#3f7f5f">//&nbsp;Initialize&nbsp;main&nbsp;layout</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">ExpandLayout&nbsp;layout&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">ExpandLayout</font><font color="#000000">(</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">ExpandLayout.ORIENTATION_VERTICAL</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.addComponent</font><font color="#000000">(</font><font color="#000000">showSrc</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.setComponentAlignment</font><font color="#000000">(</font><font color="#000000">showSrc,&nbsp;AlignmentHandler.ALIGNMENT_RIGHT,</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">AlignmentHandler.ALIGNMENT_TOP</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.addComponent</font><font color="#000000">(</font><font color="#000000">visibleSlide</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.setComponentAlignment</font><font color="#000000">(</font><font color="#000000">visibleSlide,</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">AlignmentHandler.ALIGNMENT_TOP</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.addComponent</font><font color="#000000">(</font><font color="#000000">covers</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.setComponentAlignment</font><font color="#000000">(</font><font color="#000000">covers,</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER,</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">AlignmentHandler.ALIGNMENT_TOP</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.expand</font><font color="#000000">(</font><font color="#000000">visibleSlide</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">layout.setSizeFull</font><font color="#000000">()</font><font color="#000000">;</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>return&nbsp;</b></font><font color="#000000">layout;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#7f0055"><b>private&nbsp;</b></font><font color="#000000">String&nbsp;getSourceCodeForThisClass</font><font color="#000000">()&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">String&nbsp;code&nbsp;=&nbsp;</font><font color="#2a00ff">&#34;Could&nbsp;not&nbsp;find&nbsp;source-file&#34;</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>try&nbsp;</b></font><font color="#000000">{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">InputStream&nbsp;is&nbsp;=&nbsp;</font><font color="#7f0055"><b>this</b></font><font color="#000000">.getClass</font><font color="#000000">()</font><font color="#000000">.getResource</font><font color="#000000">(</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#2a00ff">&#34;CoverflowApplication.html&#34;</font><font color="#000000">)</font><font color="#000000">.openStream</font><font color="#000000">()</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">BufferedReader&nbsp;r&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">BufferedReader</font><font color="#000000">(</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">InputStreamReader</font><font color="#000000">(</font><font color="#000000">is</font><font color="#000000">))</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">StringBuffer&nbsp;buf&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">StringBuffer</font><font color="#000000">()</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">String&nbsp;line;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>while&nbsp;</b></font><font color="#000000">((</font><font color="#000000">line&nbsp;=&nbsp;r.readLine</font><font color="#000000">())&nbsp;</font><font color="#000000">!=&nbsp;</font><font color="#7f0055"><b>null</b></font><font color="#000000">)&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">buf.append</font><font color="#000000">(</font><font color="#000000">line</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">code&nbsp;=&nbsp;buf.toString</font><font color="#000000">()</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}&nbsp;</font><font color="#7f0055"><b>catch&nbsp;</b></font><font color="#000000">(</font><font color="#000000">IOException&nbsp;ignored</font><font color="#000000">)&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>return&nbsp;</b></font><font color="#000000">code;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff"></font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#7f0055"><b>private&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font><font color="#000000">addSlidesToCoverflow</font><font color="#000000">()&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>for&nbsp;</b></font><font color="#000000">(</font><font color="#7f0055"><b>int&nbsp;</b></font><font color="#000000">i&nbsp;=&nbsp;</font><font color="#990000">1</font><font color="#000000">;&nbsp;i&nbsp;&lt;=&nbsp;</font><font color="#990000">22</font><font color="#000000">;&nbsp;i++</font><font color="#000000">)&nbsp;{</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">String&nbsp;head&nbsp;=&nbsp;</font><font color="#2a00ff">&#34;../../../IMAGES/&#34;</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">String&nbsp;tail&nbsp;=&nbsp;</font><font color="#2a00ff">&#34;slideshow-example.0&#34;&nbsp;</font><font color="#000000">+&nbsp;</font><font color="#000000">((</font><font color="#000000">i&nbsp;&lt;&nbsp;</font><font color="#990000">10</font><font color="#000000">)&nbsp;</font><font color="#000000">?&nbsp;</font><font color="#2a00ff">&#34;0&#34;&nbsp;</font><font color="#000000">:&nbsp;</font><font color="#2a00ff">&#34;&#34;</font><font color="#000000">)&nbsp;</font><font color="#000000">+&nbsp;i</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">+&nbsp;</font><font color="#2a00ff">&#34;.jpg&#34;</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">ThemeResource&nbsp;slide&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">ThemeResource</font><font color="#000000">(</font><font color="#000000">head&nbsp;+&nbsp;tail</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">covers.addItem</font><font color="#000000">(</font><font color="#000000">slide</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">covers.setItemIcon</font><font color="#000000">(</font><font color="#000000">slide,</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">ThemeResource</font><font color="#000000">(</font><font color="#000000">head&nbsp;+&nbsp;</font><font color="#2a00ff">&#34;thumbs/&#34;&nbsp;</font><font color="#000000">+&nbsp;tail</font><font color="#000000">))</font><font color="#000000">;</font><br />
+<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#ffffff">&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#000000">}</font></code>
+
+ </td>
+ <!-- end source code -->
+ </tr>
+</table>
+</div>
+<!-- = END of automatically generated HTML code = -->
+<!-- ======================================================== -->
+
+
+</body></html> \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/CoverflowApplication.java b/src/com/vaadin/demo/coverflow/CoverflowApplication.java
new file mode 100644
index 0000000000..25b5ddaa64
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/CoverflowApplication.java
@@ -0,0 +1,114 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.coverflow;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import com.vaadin.data.Property;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class CoverflowApplication extends com.vaadin.Application {
+
+ Coverflow covers = new Coverflow();
+
+ public void init() {
+
+ setMainWindow(new Window("Coverflow", createMainLayout()));
+
+ setTheme("coverflow");
+
+ addSlidesToCoverflow();
+ }
+
+ private VerticalLayout createMainLayout() {
+
+ // Initialize coverflow component
+ covers.setHeight("150px");
+ covers.setWidth("100%");
+ covers.setBackgroundColor(0, 0, 0, 100, 100, 100);
+
+ // Initialize visible slide viewer
+ Panel slidePanel = new Panel();
+ slidePanel.setStyleName(Panel.STYLE_LIGHT);
+ slidePanel.setSizeFull();
+ final Embedded visibleSlide = new Embedded();
+ visibleSlide.setHeight("480px");
+ slidePanel.addComponent(visibleSlide);
+ ((VerticalLayout) slidePanel.getLayout()).setComponentAlignment(
+ visibleSlide, "center");
+
+ // Listen to coverflow changes as change slides when needed
+ covers.addListener(new Property.ValueChangeListener() {
+ public void valueChange(Property.ValueChangeEvent event) {
+ visibleSlide.setSource((Resource) covers.getValue());
+ }
+ });
+
+ // Show sources button
+ Button showSrc = new Button("Show source", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Window srcWindow = new Window("Source code");
+ srcWindow.setWidth("700px");
+ srcWindow.setHeight("500px");
+ Label l = new Label(getSourceCodeForThisClass(),
+ Label.CONTENT_XHTML);
+ srcWindow.addComponent(l);
+ getMainWindow().addWindow(srcWindow);
+ }
+ });
+ showSrc.setStyleName(Button.STYLE_LINK);
+ // Initialize main layout
+ VerticalLayout layout = new VerticalLayout();
+ layout.addComponent(showSrc);
+ layout.setComponentAlignment(showSrc, Alignment.TOP_RIGHT);
+ layout.addComponent(slidePanel);
+ layout.addComponent(covers);
+ layout.setExpandRatio(slidePanel, 1);
+ layout.setSizeFull();
+
+ return layout;
+ }
+
+ private String getSourceCodeForThisClass() {
+ String code = "Could not find source-file";
+ try {
+ InputStream is = this.getClass().getResource(
+ "CoverflowApplication.html").openStream();
+ BufferedReader r = new BufferedReader(new InputStreamReader(is));
+ StringBuffer buf = new StringBuffer();
+ String line;
+ while ((line = r.readLine()) != null) {
+ buf.append(line);
+ }
+ code = buf.toString();
+ } catch (IOException ignored) {
+ }
+ return code;
+ }
+
+ private void addSlidesToCoverflow() {
+ for (int i = 0; i < 20; i++) {
+ String head = "images/";
+ String tail = "slideshow-example.0" + ((i < 10) ? "0" : "") + i
+ + ".jpg";
+ ThemeResource slide = new ThemeResource(head + tail);
+ covers.addItem(slide);
+ covers.setItemIcon(slide,
+ new ThemeResource(head + "thumbs/" + tail));
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/coverflow/gwt/CoverflowWidgetSet.gwt.xml b/src/com/vaadin/demo/coverflow/gwt/CoverflowWidgetSet.gwt.xml
new file mode 100644
index 0000000000..36c016f131
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/CoverflowWidgetSet.gwt.xml
@@ -0,0 +1,8 @@
+<module>
+ <!-- Inherit the NoEntry version to avoid multiple entrypoints -->
+ <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSetNoEntry" />
+
+ <!-- Entry point -->
+ <entry-point class="com.vaadin.demo.coverflow.gwt.client.CoverflowWidgetSet"/>
+
+</module>
diff --git a/src/com/vaadin/demo/coverflow/gwt/client/CoverflowWidgetSet.java b/src/com/vaadin/demo/coverflow/gwt/client/CoverflowWidgetSet.java
new file mode 100644
index 0000000000..38037a4ba0
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/client/CoverflowWidgetSet.java
@@ -0,0 +1,34 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.coverflow.gwt.client;
+
+import com.vaadin.demo.coverflow.gwt.client.ui.ICoverflow;
+import com.vaadin.terminal.gwt.client.DefaultWidgetSet;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class CoverflowWidgetSet extends DefaultWidgetSet {
+ /** Creates a widget according to its class name. */
+ public Paintable createWidget(UIDL uidl) {
+ final Class classType = resolveWidgetType(uidl);
+ if (ICoverflow.class == classType) {
+ return new ICoverflow();
+ }
+
+ // Let the DefaultWidgetSet handle creation of default widgets
+ return super.createWidget(uidl);
+ }
+
+ /** Resolves UIDL tag name to class . */
+ protected Class resolveWidgetType(UIDL uidl) {
+ final String tag = uidl.getTag();
+ if ("cover".equals(tag)) {
+ return ICoverflow.class;
+ }
+
+ // Let the DefaultWidgetSet handle resolution of default widgets
+ return super.resolveWidgetType(uidl);
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/client/ui/ICoverflow.java b/src/com/vaadin/demo/coverflow/gwt/client/ui/ICoverflow.java
new file mode 100644
index 0000000000..c09d18c7d8
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/client/ui/ICoverflow.java
@@ -0,0 +1,336 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.coverflow.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class ICoverflow extends Composite implements Paintable {
+ private String uidlId;
+ protected ApplicationConnection client;
+ private ArrayList coverList = new ArrayList();
+
+ private Object _selected;
+ private boolean flashInited = false;
+ private HTML flash;
+ private boolean scrollbarVisibility = true;
+ private String backgroundGradientStart;
+ private String backgroundGradientEnd;
+ private boolean colorChanged = false;
+ private boolean sbVisibilityChanged = false;
+ private HashMap keyMap = new HashMap();
+
+ /**
+ * Constructor
+ */
+ public ICoverflow() {
+ flash = new HTML();
+
+ initWidget(flash);
+ }
+
+ /**
+ * This method accepts parses the uidl sent by the server
+ *
+ * @param UIDL
+ * uidl
+ * @param ApplicationConnection
+ * client
+ */
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Store variables
+ uidlId = uidl.getId();
+ this.client = client;
+ String tempColor;
+
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ // Has the scrollbar's visibility status changed?
+ if (uidl.hasAttribute("scrollbarVisibility")) {
+ boolean tempVis = uidl.getBooleanAttribute("scrollbarVisibility");
+ if (scrollbarVisibility != tempVis) {
+ scrollbarVisibility = tempVis;
+ sbVisibilityChanged = true;
+ }
+ }
+
+ // Has the start gradient changed?
+ if (uidl.hasAttribute("backgroundGradientStart")) {
+ tempColor = uidl.getStringAttribute("backgroundGradientStart")
+ .toString();
+ if (tempColor != backgroundGradientStart) {
+ backgroundGradientStart = tempColor;
+ colorChanged = true;
+ }
+ }
+
+ // Has the end gradient changed?
+ if (uidl.hasAttribute("backgroundGradientEnd")) {
+ tempColor = uidl.getStringAttribute("backgroundGradientEnd")
+ .toString();
+ if (tempColor != backgroundGradientEnd) {
+ backgroundGradientEnd = tempColor;
+ colorChanged = true;
+ }
+ }
+
+ final UIDL images = uidl.getChildUIDL(0);
+
+ // Check which covers should be removed. This array list contains all
+ // current
+ // covers. We remove from this list all covers which are sent with the
+ // repainted
+ // uidl. All remaining covers in this list should be "old" ones and are
+ // should
+ // be deleted.
+
+ ArrayList newList = new ArrayList();
+
+ // Iterate through all option elements
+ for (final Iterator i = images.getChildIterator(); i.hasNext();) {
+ final UIDL imgUidl = (UIDL) i.next();
+
+ // Make sure all required attributes exist
+ if (imgUidl.hasAttribute("caption") && imgUidl.hasAttribute("key")
+ && imgUidl.hasAttribute("icon")) {
+ HashMap set = new HashMap();
+
+ // Update the key map
+ keyMap.put(imgUidl.getStringAttribute("caption"), imgUidl
+ .getStringAttribute("key"));
+
+ // Get information
+
+ set.put("icon", client.translateToolkitUri(imgUidl
+ .getStringAttribute("icon")));
+ set.put("caption", imgUidl.getStringAttribute("caption"));
+
+ newList.add(set);
+
+ // Is the current cover selected?
+ if (imgUidl.hasAttribute("selected")) {
+ _selected = imgUidl.getStringAttribute("caption");
+ }
+ }
+ }
+
+ // Deleted items
+ ArrayList intersectList = new ArrayList();
+ intersectList.addAll(coverList);
+ intersectList.removeAll(newList);
+
+ if (flashInited) {
+ for (int i = 0; i < intersectList.size(); i++) {
+ HashMap cover = (HashMap) intersectList.get(i);
+ removeCover(uidlId, cover.get("caption").toString());
+ }
+ }
+
+ // Added items
+ intersectList = new ArrayList();
+ intersectList.addAll(newList);
+ intersectList.removeAll(coverList);
+
+ if (flashInited) {
+ for (int i = 0; i < intersectList.size(); i++) {
+ HashMap cover = (HashMap) intersectList.get(i);
+ addCover(uidlId, cover.get("caption").toString(), cover.get(
+ "icon").toString());
+ }
+ }
+
+ coverList = newList;
+
+ // Has the flash been initialized?
+ if (!flashInited) {
+ colorChanged = false;
+ setFlash();
+ initializeMethods(uidlId);
+ }
+
+ // Inform flash of the selected cover
+ if (_selected != null && flashInited) {
+ selectCover(uidlId, _selected.toString());
+ }
+
+ if (colorChanged && flashInited) {
+ setBackgroundColor(uidlId, backgroundGradientStart,
+ backgroundGradientEnd);
+ colorChanged = false;
+ }
+
+ if (sbVisibilityChanged && flashInited) {
+ toggleScrollbarVisibility(uidlId, scrollbarVisibility);
+ sbVisibilityChanged = false;
+ }
+
+ }
+
+ /**
+ * Inform the server which cover is selected
+ *
+ * @param String
+ * coverKey
+ */
+ public void setCover(String coverId) {
+ if (uidlId == null || client == null) {
+ return;
+ }
+
+ client.updateVariable(uidlId, "selected", new String[] { keyMap.get(
+ coverId).toString() }, true);
+ }
+
+ /**
+ * Initialize the native javascript functions needed for the flash <-> GWT
+ * communication
+ *
+ * @param String
+ * id
+ */
+ public native void initializeMethods(String id) /*-{
+ var app = this;
+
+ if($wnd.itmill.coverflow == null)
+ var coverflow = [];
+ else
+ var coverflow = $wnd.itmill.coverflow;
+
+ coverflow['getCovers_' + id] = function() {
+ app.@com.vaadin.demo.coverflow.gwt.client.ui.ICoverflow::getCovers()();
+ };
+
+ coverflow['setCurrent_' + id] = function(selected) {
+ app.@com.vaadin.demo.coverflow.gwt.client.ui.ICoverflow::setCover(Ljava/lang/String;)(selected);
+ };
+
+ $wnd.itmill.coverflow = coverflow;
+ }-*/;
+
+ /**
+ * This function sends all covers to the flash. We cannot do this directly
+ * in the updateFromUIDL method, because we cannot be sure if the flash has
+ * been loaded into the browser. The flash will call for this method when
+ * it's ready.
+ */
+ public void getCovers() {
+ // Loop through all stored coves
+ for (int i = 0; i < coverList.size(); i++) {
+ HashMap set = (HashMap) coverList.get(i);
+
+ try {
+ // Add the cover
+ addCover(uidlId, set.get("caption").toString(), set.get("icon")
+ .toString());
+ } catch (Exception e) {
+ // Do not add covers lacking obligatory data
+ }
+ }
+ // The flash calls for this method, therefore we can be sure that the
+ // flash has been loaded
+ // into the browser.
+ flashInited = true;
+
+ // Set selected cover
+ if (_selected != null) {
+ selectCover(uidlId, _selected.toString());
+ }
+ }
+
+ /**
+ * This function is a native javascript function which adds covers to the
+ * actual flash. This method works as a bridge between GWT and flash.
+ *
+ * @param id
+ * @param key
+ * @param caption
+ * @param icon
+ */
+ public native void addCover(String id, String caption, String icon) /*-{
+ try {
+ $doc['fxcoverflow' + id].addCover(caption.toString(), icon.toString());
+ }
+ catch(e) {
+ $wnd.alert(e.message);
+ }
+
+ }-*/;
+
+ /**
+ * This function tells the flash which cover should be selected.
+ *
+ * @param id
+ * @param key
+ */
+ public native void selectCover(String id, String key) /*-{
+ $doc["fxcoverflow" + id].selectCover(key.toString());
+ }-*/;
+
+ public native void setBackgroundColor(String id, String startGradient,
+ String endGradient) /*-{
+ $doc["fxcoverflow" + id].setBackgroundColor("0x" + startGradient.toString(), "0x" + endGradient.toString());
+ }-*/;
+
+ public native void toggleScrollbarVisibility(String id, boolean visibility) /*-{
+ $doc["fxcoverflow" + id].toggleScrollbarVisibility(visibility);
+ }-*/;
+
+ public native void removeCover(String id, String key) /*-{
+ $doc["fxcoverflow" + id].removeCover(key);
+ }-*/;
+
+ /**
+ * Set the HTML coding of the flash movie. This isn't done until the
+ * updateFromUIDL method is called for the first time. The reason is that we
+ * use an id from the UIDL to uniquely identify all instances of this
+ * widget.
+ */
+ private void setFlash() {
+ String html = "<object id=\"fxcoverflow"
+ + uidlId
+ + "\" classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"100%\""
+ + " height=\"100%\" codebase=\"http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0\">"
+ + "<param name=\"movie\" value=\""
+ + GWT.getModuleBaseURL()
+ + "coverflowflash.swf\">"
+ + "<param name=\"quality\" value=\"high\">"
+ + "<param name=\"flashVars\" value=\"pid="
+ + uidlId
+ + "&sbVis="
+ + scrollbarVisibility
+ + "&bgS=0x"
+ + backgroundGradientStart
+ + "&bgE=0x"
+ + backgroundGradientEnd
+ + "\" />"
+ + "<embed name=\"fxcoverflow"
+ + uidlId
+ + "\" flashVars=\"pid="
+ + uidlId
+ + "&sbVis="
+ + scrollbarVisibility
+ + "&bgS=0x"
+ + backgroundGradientStart
+ + "&bgE=0x"
+ + backgroundGradientEnd
+ + "\" src=\""
+ + GWT.getModuleBaseURL()
+ + "coverflowflash.swf\" width=\"100%\" height=\"100%\" "
+ + "quality=\"high\" "
+ + "pluginspage=\"http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash\">"
+ + "</embed>" + "</object>";
+ flash.setHTML(html);
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/flex/Cover.as b/src/com/vaadin/demo/coverflow/gwt/flex/Cover.as
new file mode 100644
index 0000000000..61b08ead48
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/flex/Cover.as
@@ -0,0 +1,392 @@
+package {
+ import flash.events.Event;
+ import flash.display.Loader;
+ import flash.display.DisplayObject;
+ import flash.system.LoaderContext;
+ import flash.display.Bitmap;
+ import flash.display.BitmapData;
+ import flash.net.URLRequest;
+ import mx.controls.Alert;
+
+ import flash.system.Security;
+ import flash.system.ApplicationDomain;
+
+ import mx.controls.Image;
+ import mx.core.UIComponent;
+ import flash.geom.Matrix;
+ import flash.display.Sprite;
+ import flash.display.Shape;
+ import flash.display.Graphics;
+ import flash.display.GradientType;
+ import flash.geom.Rectangle;
+ import flash.geom.Point;
+
+ import sandy.util.*;
+
+ public class Cover extends UIComponent {
+ // Cover information
+ private var _caption:String;
+ private var _uri:String;
+ private var _imageLoaded:Boolean = false;
+
+ // Actual content information
+ private var _bitmapData:BitmapData;
+ private var _bitmap:Bitmap;
+ private var _img:Image;
+ private var _distortedShape:Shape;
+ private var _reflectionBitmap:Bitmap;
+ private var _reflectionShape:Shape;
+
+
+ // Distort information
+ private var _realAngle:Number = -1;
+ private var _realScale:Number = -1;
+ private var _angle:Number = 0;
+ private var _scale:Number = 1;
+ private static const perspectiveConstant:Number = .15;
+
+
+ // Position information
+ private var _x:int;
+ private var _y:int;
+
+ /**
+ * Constructor
+ */
+ public function Cover(caption:String, uri:String) {
+ super();
+
+ // Set this element's size to 100% x 100%
+ super.percentHeight = 100;
+ super.percentWidth = 100;
+
+ // Store input data
+ this._caption = caption;
+ this._uri = uri;
+
+ // Initialize default image
+ this._img = new Image();
+ this._img.percentHeight = 100;
+ this._img.percentWidth = 100;
+ this._bitmapData = new BitmapData(100,100,false, 0xffff0000);
+
+ _distortedShape = new Shape();
+ addChild(_distortedShape);
+
+ _reflectionShape = new Shape();
+ addChild(_reflectionShape);
+
+ // Create the default image
+ this._img.source = this.getBitmap();
+
+ addChildAt(_img, 0);
+ }
+
+ /**
+ * Load an image if it hasn't been loaded yet
+ */
+ public function loadImage():void {
+ if(!_imageLoaded) {
+ // Create a loader to load the image
+ var request:URLRequest = new URLRequest(this._uri);
+ var imageLoader:Loader = new Loader();
+
+ // Check for restrictions
+ var imgLdrContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
+ imgLdrContext.checkPolicyFile = true;
+
+ // Set an event listener
+ imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imgLoaded);
+
+ // Load the image
+ imageLoader.load(request, imgLdrContext);
+ }
+ }
+
+ /**
+ * Event handler for image load completion
+ * @param Event event
+ */
+ private function imgLoaded(event:Event):void {
+ // Check if we got the image
+ try {
+ removeChild(_img);
+ this._bitmapData = Bitmap(event.currentTarget.content).bitmapData;
+
+ // Set new source for the image
+ this._img.source = this.getBitmap();
+ addChildAt(_img, 0);
+
+ _imageLoaded = true;
+ invalidateDisplayList();
+ }
+ catch(error:Error) {
+ // An error occured
+ Alert.show(error.toString());
+ }
+ }
+
+ /**
+ * Measure the size of the image
+ */
+ override protected function measure():void {
+ if(_img != null)
+ {
+ measuredHeight = _img.getExplicitOrMeasuredHeight();
+ measuredWidth = _img.getExplicitOrMeasuredWidth();
+ }
+ }
+
+ /**
+ * Update the image on the display
+ */
+ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
+ // Do this if and only iff the angle or the scale has changed. Otherwise we do not
+ // want to re-draw the image, only move it.
+ if(_img && (_realAngle != _angle || _realScale != _scale))
+ {
+ var contentWidth:Number = _img.getExplicitOrMeasuredWidth();
+ var contentHeight:Number= _img.getExplicitOrMeasuredHeight();
+
+ _img.setActualSize(contentWidth,contentHeight);
+
+ _realAngle = _angle;
+ _realScale = _scale;
+
+ // Distort the image
+ distortImage(_bitmap, _distortedShape, false);
+
+ // Create a reflection
+ createReflectionBitmap(_bitmap);
+ }
+ }
+
+ /**
+ * This function distorts the target according to its angle
+ * @param Bitmap bm - The bitmap of the object which is being distorted
+ * @param Shape target - The target where the distorted image is stored
+ * @param Boolean refelection - Is this target a reflection?
+ */
+ private function distortImage(bm:Bitmap, target:Shape, reflection:Boolean):void {
+ // Turn the angle into a value between 0 and 1
+ var k:Number = (Math.abs(_angle)/90);
+ k = Math.sqrt(k);
+
+ var vShear:Number = (_angle >= 0)? k*-perspectiveConstant : k*perspectiveConstant;
+ var verticalOffset:Number;
+
+ // How much is the width of the image scaled
+ var hScale:Number = 1 - k;
+
+ // How much lower/higher are the corners "further away" than the one "closer"
+ verticalOffset = (_img.getExplicitOrMeasuredHeight()*vShear);
+
+ // Is this image a reflection? If yes, then the vertical offset distortion is made in another direction
+ if(reflection)
+ verticalOffset *= -1;
+
+ // Initialize the distortion class
+ var distort:DistortImage = new DistortImage();
+ distort.container = target;
+ distort.target = bm;
+ distort.smooth = true;
+ distort.initialize( 5, 5, null );
+
+ // Distort the images to the left
+ if(_angle > 0) {
+ distort.setTransform(
+ 0,0,
+ _img.getExplicitOrMeasuredWidth()*hScale,-verticalOffset,
+ _img.getExplicitOrMeasuredWidth()*hScale,_img.getExplicitOrMeasuredHeight()+verticalOffset,
+ 0,_img.getExplicitOrMeasuredHeight()
+ );
+ }
+ // Distort the images to the right
+ else if(_angle < 0) {
+ distort.setTransform(
+ 0,verticalOffset,
+ _img.getExplicitOrMeasuredWidth()*hScale,0,
+ _img.getExplicitOrMeasuredWidth()*hScale,_img.getExplicitOrMeasuredHeight(),
+ 0,_img.getExplicitOrMeasuredHeight()-verticalOffset
+ );
+ }
+ distort.render();
+
+ // We use the original image as a reference, but do not want to show it on the screen
+ _img.visible = false;
+
+ // Align the distorted image correctly
+ var m:Matrix = target.transform.matrix;
+ m.tx = 0 - _img.width/2* hScale;
+ target.transform.matrix = m;
+ }
+
+ /**
+ * This function creates a reflection of the target object
+ * @param DisplayObject target
+ */
+ private function createReflectionBitmap(target:DisplayObject):void {
+ // Size of the fade
+ var fadeSize:Number = 0.4;
+
+ // Create a rectangle
+ var box:Rectangle = new Rectangle(0, 0, target.width, target.height);
+
+ // Create a matrix for the gradient
+ var gradientMatrix: Matrix = new Matrix();
+ // Create a shape object for the gradient
+ var gradientShape: Shape = new Shape();
+ // Apply a gradient on the matrix
+ gradientMatrix.createGradientBox(target.width, target.height * fadeSize, Math.PI/2, 0, target.height * (1.0 - fadeSize));
+
+ // Fill the shape with the gradient
+ gradientShape.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0xFFFFFF], [0, 1], [0, 255], gradientMatrix);
+ gradientShape.graphics.drawRect(0, target.height * (1.0 - fadeSize), target.width, target.height * fadeSize);
+ gradientShape.graphics.endFill();
+
+ // Bitmap representation of the gradient
+ var gradientBm:BitmapData = new BitmapData(target.width, target.height, true, 0x00000000);
+ gradientBm.draw(gradientShape, new Matrix());
+
+ var targetBm:BitmapData = new BitmapData(target.width, target.height, true, 0x00000000);
+ targetBm.fillRect(box, 0x00000000);
+ targetBm.draw(target, new Matrix());
+
+ var reflectionData:BitmapData = new BitmapData(target.width, target.height, true, 0x00000000);
+ reflectionData.fillRect(box, 0x00000000);
+ reflectionData.copyPixels(targetBm, box, new Point(), gradientBm);
+
+ // Store the reflection
+ _reflectionBitmap = new Bitmap(reflectionData);
+
+ // Move the reflection to its correct position
+ var m:Matrix = _distortedShape.transform.matrix;
+ m.d = -1;
+ m.ty = _distortedShape.height*2;
+ _reflectionShape.transform.matrix = m;
+
+ // Distort the reflection
+ distortImage(_reflectionBitmap, _reflectionShape, true);
+
+ // Set a transparancy for the reflection
+ _reflectionShape.alpha = 0.4;
+
+ }
+
+ /**
+ * Get name
+ * @return String
+ */
+ public function get caption():String {
+ return this._caption;
+ }
+
+ /**
+ * Set name
+ * @param String name
+ */
+ public function set caption(caption:String):void {
+ this._caption = caption;
+ }
+
+ /**
+ * Get uri
+ * @return String
+ */
+ public function get uri():String {
+ return this._uri;
+ }
+
+ /**
+ * Set uri
+ * @param String uri
+ */
+ public function set uri(uri:String):void {
+ this._uri = uri;
+ }
+
+ /**
+ * Get the bitmap
+ * @return Bitmap
+ */
+ public function getBitmap():Bitmap {
+ this._bitmap = new Bitmap(this._bitmapData);
+ return this._bitmap;
+ }
+
+ /**
+ * Get the bitmap data
+ * @return BitmapData
+ */
+ public function getBitmapData():BitmapData {
+ return this._bitmapData;
+ }
+
+ /**
+ * Set the angle of the cover
+ * @param Number angle
+ */
+ public function set angle(angle:Number):void {
+ this._angle = angle;
+ invalidateDisplayList();
+ }
+
+ /**
+ * Get the angle of the cover
+ * @return Number
+ */
+ public function get angle():Number {
+ return this._angle;
+ }
+
+ /**
+ * Set the x position of the cover
+ * @param Number x
+ */
+ public function set xPos(x:Number):void {
+ this._x = x;
+ }
+
+ /**
+ * Get the x position of the cover
+ * @return Number
+ */
+ public function get xPos():Number {
+ return this._x;
+ }
+
+ /**
+ * Set the y position of the cover
+ * @param Number y
+ */
+ public function set yPos(y:Number):void {
+ this._y = y;
+ }
+
+ /**
+ * Get the y position of the cover
+ * @return Number
+ */
+ public function get yPos():Number {
+ return this._y;
+ }
+
+ /**
+ * Set the scale of the cover
+ * @param Number scale
+ */
+ public function set scale(scale:Number):void {
+ this._scale = scale;
+ }
+
+ /**
+ * Get the scale position of the cover
+ * @return Number
+ */
+ public function get scale():Number {
+ return this._scale;
+ }
+
+ }
+}
+ \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/flex/Coverflow.as b/src/com/vaadin/demo/coverflow/gwt/flex/Coverflow.as
new file mode 100644
index 0000000000..38d924b7dd
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/flex/Coverflow.as
@@ -0,0 +1,598 @@
+package {
+ import flash.events.Event;
+ import flash.events.MouseEvent;
+ import flash.utils.Dictionary;
+ import flash.geom.Matrix;
+
+ import mx.controls.Alert;
+ import mx.controls.Image;
+ import mx.controls.HScrollBar;
+ import mx.core.UIComponent;
+ import mx.core.Application;
+ import mx.effects.AnimateProperty;
+ import mx.effects.easing.Quadratic;
+ import flash.external.ExternalInterface;
+ import mx.events.ScrollEvent;
+
+ public class Coverflow extends UIComponent {
+ // The scrollbar
+ private var _scrollbar:HScrollBar;
+
+ // _coverList is an array containing all the coverflow objects
+ private var _coverList:Array = new Array();
+
+ // Which element is selected
+ private var _selected:int = -1;
+
+ // Which element is currently being showed
+ private var _current:Number = 0;
+
+ // How much space (in pixels) is there between each cover
+ private var _coverSpacing:int = 40;
+
+ // A map between covers and their positions in the coverflow
+ private var _coverMap:Dictionary;
+
+ // The angle in which the child covers are distorted
+ private static const _angle:int = 35;
+
+ // The size of the child covers. The default value is 0.8 which means that
+ // the child covers are 80% of their maximum size
+ private static const _childScale:Number = 0.8;
+
+ // All covers are scaled to the maximum. These two variables tell us how
+ // big a cover can be in maximum
+ private var _maxWidth:int;
+ private var _maxHeight:int;
+
+ // An object which takes care of animations
+ private var _animation:AnimateProperty;
+
+ // An object for event handling
+ private var _eventHandler:EventHandler = new EventHandler();
+
+ // The unique identifier of this instance of the widget
+ private var _pid:String;
+
+ // Has the cover list's content changed?
+ private var _listChanged:Boolean = false;
+
+ /**
+ * Constructor
+ */
+ public function Coverflow():void {
+ super();
+
+ // Initialize the scrollbar
+ _scrollbar = new HScrollBar();
+ _scrollbar.x = 0;
+ // Add an action listener to the scrollbar which detects when the
+ // scrollbar's position has been changed. This event should also
+ // change the selected cover's value
+ _scrollbar.addEventListener(ScrollEvent.SCROLL, function ():void { selectedCover = Math.round(_scrollbar.scrollPosition); });
+
+ // Maximize the size of the component
+ this.percentHeight = 100;
+ this.percentWidth = 100;
+
+ }
+
+ /**
+ * This function is called when the flash has finished loading. This
+ * function will intialize the communication interface between flash
+ * and GWT.
+ */
+ private function init():void {
+ // Are we even able to initialize a external communication interface?
+ if (ExternalInterface.available) {
+ // These two methods are made available for javascript (they
+ // can be directly called within javascript code)
+ ExternalInterface.addCallback("addCover", this.addCover);
+ ExternalInterface.addCallback("selectCover", this.externalSetCover);
+ ExternalInterface.addCallback("setBackgroundColor", this.setBackgroundColor);
+ ExternalInterface.addCallback("toggleScrollbarVisibility", this.toggleScrollbarVisibility);
+ ExternalInterface.addCallback("removeCover", this.removeCover);
+
+ // Try to call a javascript function
+ try {
+ // The function we want to call is getCovers. It tells javascript
+ // that the flash is now ready to accept information of the covers.
+ // The name of the function we're about to call is dynamic, meaning
+ // it is unique for every instance of this widget
+ ExternalInterface.call("itmill.coverflow['getCovers_" + _pid + "']");
+ } catch (error:SecurityError) {
+ Alert.show("A SecurityError occurred: " + error.message + "\n");
+ } catch (error:Error) {
+ Alert.show("An Error occurred: " + error.message + "\n");
+ }
+ } else {
+ Alert.show("External interface is not available for this container.");
+ }
+ }
+
+ /**
+ * Adds a new cover to the coverflow list
+ * @param String name
+ * @param String uri
+ */
+ private function addCover(name:String, uri:String):void {
+ // Create an instance of the cover object
+ var cover:Cover = new Cover(name.toString(), uri.toString());
+
+ // Mark the list as being modified
+ _listChanged = true;
+
+ // Load the image
+ cover.loadImage();
+ // Add the cover to our array
+ _coverList.push(cover);
+ commitProperties();
+ }
+
+ /**
+ * Measure the size of this component
+ */
+ override protected function measure():void {
+ super.measure();
+
+ // What is the maximum size of a cover? It is either 3/4 of the height of the component
+ // or 1/3 of the width - which ever is smaller.
+ _maxHeight = _maxWidth = Math.round(Math.min(this.width/3,this.height/4*3));
+ }
+
+ /**
+ * Creates the child elements (covers)
+ */
+ override protected function createChildren():void {
+ super.createChildren();
+
+ for(var i:int = 0; i < _coverList.lenght; i++)
+ addChild(_coverList[i]);
+
+ invalidateDisplayList();
+ }
+
+ /**
+ * Something has changed
+ */
+ override protected function commitProperties():void {
+ // Remove all old covers
+ for(i = numChildren-1;i>=0;i--) {
+ removeChildAt(numChildren-1);
+ }
+
+ // Create a new mapping between the covers and their position
+ _coverMap = new Dictionary(true);
+
+ // Loop through the coverlist array
+ for(var i:int = 0;i<_coverList.length;i++) {
+ var cover:Cover = _coverList[i];
+ // Make sure the cover is loaded
+ cover.loadImage();
+
+ // Add an event listener to the cover. We want to know when
+ // a cover is being clicked.
+ cover.addEventListener(MouseEvent.CLICK,selectEvent,false,0,true);
+ // Add the cover to the flash movie
+ addChildAt(cover,i);
+
+ // Add this cover to the map
+ _coverMap[cover] = i;
+ }
+
+ // Add the scrollbar on top of all other elements
+ addChild(_scrollbar);
+
+ // Update the scrollbar's details
+ invalidateScrollbar();
+
+ // update screen
+ invalidateDisplayList();
+ }
+
+ /**
+ * This function draws the actual content of the flash movie
+ */
+ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
+ if(_selected < 0) {
+ selectedCover = 0;
+ return;
+ }
+
+ // Measure the size of the component
+ measure();
+ // Update the scrollbar's details
+ invalidateScrollbar();
+
+ // Check if there are any new covers added to our array
+ if(_listChanged) {
+ _eventHandler.dispatchEvent(new Event(EventHandler.DATA_CHANGED));
+ _listChanged = false;
+ }
+
+ // If no covers exist, then do nothing
+ if(_coverList.length == 0)
+ return;
+
+
+ var cover:Cover;
+ var index:int = 0;
+ var m:Matrix;
+
+ // Loop through all covers
+ for(var i:int=0; i < _coverList.length; i++) {
+ cover = _coverList[i];
+
+ // Calculate in which layer position the cover should be
+ index = (i <= Math.floor(_current))? i : _coverList.length-1-i;
+
+ // Set the real size of the cover
+ cover.setActualSize(cover.getExplicitOrMeasuredWidth(),cover.getExplicitOrMeasuredHeight());
+
+ // Calculate in which angle the cover should be at this specific moment
+ calculateAngle(cover, i);
+
+ // Set the covers layer position
+ setChildIndex(cover,index);
+
+ // Calculate the cover's size (scale)
+ calculateScale(cover, i);
+
+ // ...and finally calculate its position (horizontal position, that is)
+ calculatePosition(cover, i);
+
+ // Resize the cover according to its scale value
+ m = cover.transform.matrix;
+ m.a = m.d = cover.scale;
+ cover.transform.matrix = m;
+
+ // Move the cover to its correct position
+ cover.move(cover.xPos, cover.yPos);
+
+ }
+ // Set selected cover on top of all other covers
+ setChildIndex(_coverList[Math.floor(_current)],_coverList.length-1);
+ }
+
+ /**
+ * This function calulcates the position of a cover at any given moment.
+ * @param Cover c - Which cover is being processed
+ * @param int index - what is the cover's index (horizontal order number)
+ */
+ private function calculatePosition(c:Cover, index:int):void {
+ // All covers are aligned so, that their bottom is at 3/4's height of the
+ // actual flash movie
+ c.yPos = Math.round(unscaledHeight/4*3-c.getExplicitOrMeasuredHeight()*c.scale);
+
+ // Calculate the position difference between the currently selected item and
+ // this items index
+ var diff:Number = _current-index;
+
+ // We want to know the previous and next positions of the item
+ var prevPos:Number;
+ var nextPos:Number;
+
+ // We are currently processing a cover which comes from the left to the center (selected)
+ if(index == Math.floor(_current)) {
+ // Calculate the previous position
+ prevPos = unscaledWidth/2 - _maxWidth/2 - _coverSpacing;
+ // The next position is in the center of the screen
+ nextPos = unscaledWidth/2;
+ // Now calculate in which state of the animation we are
+ c.xPos = nextPos-diff*(nextPos-prevPos);
+ }
+ // Same as above, except now we come from right to center
+ else if(index == Math.ceil(_current)) {
+ prevPos = unscaledWidth/2;
+ nextPos = unscaledWidth/2 +_maxWidth/2 + _coverSpacing;
+ c.xPos = prevPos-diff*(nextPos-prevPos);
+ }
+ // Child covers to the left
+ else if(index < Math.floor(_current)){
+ c.xPos = unscaledWidth/2 - _maxWidth/2 - diff*_coverSpacing;
+ }
+ // ..and child covers to the right
+ else {
+ c.xPos = unscaledWidth/2 +_maxWidth/2 - diff*_coverSpacing;
+ }
+ }
+
+ /**
+ * Calulcates the angle of a cover at any given moment
+ * @param Cover c
+ * @param int index
+ */
+ private function calculateAngle(c:Cover, index:int):void {
+ // This function has the same principle as the the function above
+
+ var diff:Number;
+
+ if(index == Math.floor(_current)) {
+ diff = _current-Math.floor(_current);
+ c.angle = _angle*diff;
+ }
+ else if(index == Math.ceil(_current)) {
+ diff = _current-Math.ceil(_current);
+ c.angle = _angle*diff;
+ }
+ else if(index < Math.floor(_current))
+ c.angle = _angle;
+ else
+ c.angle = -_angle;
+ }
+
+ /**
+ * Calculates the size (scale) of a cover at any given moment
+ * @param Cover c
+ * @param int index
+ */
+ private function calculateScale(c:Cover, index:int):void {
+ // Almost same as calculatePosition, except that now we are
+ // calculating the scaled size of the cover
+
+ var diff:Number = _current-index;
+ var scalePrev:Number;
+ var scaleNext:Number;
+
+ if(index == Math.floor(_current)) {
+ scalePrev = maxScale(c.width, c.height)*_childScale;
+ scaleNext = maxScale(c.width, c.height);
+ c.scale = scaleNext-diff*(scaleNext-scalePrev);
+ }
+ else if(index == Math.ceil(_current)) {
+ scalePrev = maxScale(c.width, c.height);
+ scaleNext = maxScale(c.width, c.height)*_childScale;
+ c.scale = scalePrev-diff*(scaleNext-scalePrev);
+ }
+ else
+ c.scale = maxScale(c.width, c.height)*_childScale;
+
+
+ }
+
+ /**
+ * Calculate the maximum scale of a cover
+ * @param Number w - The actual width of the cover
+ * @param Number h - The actual height of the cover
+ * @return Number
+ */
+ private function maxScale(w:Number, h:Number):Number {
+ // The width of the cover is bigger than the height. This means that
+ // the width will be the restricting factor of this cover's size.
+ // Therefore we calculate the maximum size of this cover (result given
+ // as a scale)
+ if(w > h)
+ return _maxWidth/w;
+
+ // Height is bigger than width. Same logic as above.
+ else
+ return _maxHeight/h;
+ }
+
+ /**
+ * What happens when a user clicks on a cover?
+ * @param MouseEvent e
+ */
+ private function selectEvent(e:MouseEvent):void {
+ // Use the mapping between the covers and their positions to
+ // find out which is the index of the cover that was clicked.
+ // Set this index as the new selected cover.
+ selectedCover = _coverMap[e.currentTarget];
+ }
+
+ /**
+ * Set the selected cover
+ * @param int index
+ */
+ public function set selectedCover(index:int):void {
+ // The selected cover is already selected. Do nothing
+ if(index == _selected)
+ return;
+
+ // Validate the index, make sure it's within the coverList's range
+ if(index >= 0 && index < _coverList.length) {
+ _selected = index;
+
+ // Animate the changes
+ animateChange();
+ }
+ }
+
+ /**
+ * Returns the selected cover
+ * @return int
+ */
+ public function get selectedCover():int {
+ return _selected;
+ }
+
+ /**
+ * Set the current cover (which cover is actually being shown at this very moment.
+ * Note that the value can be a decimal value, because the selected cover can be for
+ * example 3.2, which means that it has moved 20% between the positions 3 and 4.
+ * @param Number i
+ */
+ public function set current(i:Number):void {
+ // If ExternalInterface is available and the current cover
+ // is same as the currently selected cover (in other words,
+ // the animation has finished), then send the selected cover's
+ // key to GWT which will then forward it to the server.
+ if (ExternalInterface.available && i == _selected) {
+ ExternalInterface.call("itmill.coverflow['setCurrent_" + _pid + "']",_coverList[_selected].caption);
+
+ // Send an event which notifies the scrollbar that the selected cover has changed.
+ _eventHandler.dispatchEvent(new Event(EventHandler.CURRENT_CHANGED));
+ }
+
+ // Update value
+ _current = i;
+ // Update display
+ invalidateDisplayList();
+ }
+
+ /**
+ * Get the value of current
+ * @return Number
+ */
+ public function get current():Number {
+ return _current;
+ }
+
+ /**
+ * This is a function where an external source can set the selected cover
+ * (in our case, it could be another widget which is connected to our
+ * coverflow).
+ *
+ * @param String index
+ */
+ private function externalSetCover(id:String):void {
+ var cover:Cover;
+ for(var i:int=0; i < _coverList.length; i++) {
+ cover = _coverList[i];
+
+ if(cover.caption == id) {
+ selectedCover = i;
+ break;
+ }
+ }
+ }
+
+ /**
+ * With this function we can remove any cover from the cover flow in run time
+ *
+ * @param String id
+ */
+ private function removeCover(id:String):void {
+ var cover:Cover;
+
+ // Loop through all covers and search the correct one
+ for(var i:int=0; i < _coverList.length; i++) {
+ cover = _coverList[i];
+
+ // If the cover's name matches with the given id, then delete it
+ if(cover.caption == id) {
+ // First we will however check if we are removing the last
+ // which is also currently selected
+ if(i == _coverList.length-1 && i == _selected) {
+ // Select the previous cover
+ selectedCover = i-1;
+
+ // Jump to the end of the animation
+ if(_animation != null && _animation.isPlaying)
+ _animation.end();
+ }
+
+ // Mark the list as having changes
+ _listChanged = true;
+
+ // Remove the cover from the list
+ _coverList.splice(i,1);
+
+ // Update
+ commitProperties();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gives a references to the event handler
+ * @return EventHandler
+ */
+ public function get eventHandler():EventHandler {
+ return _eventHandler;
+ }
+
+ /**
+ * Tells us how many covers there are currently added
+ * @return int
+ */
+ public function get coverCount():int {
+ return _coverList.length;
+ }
+
+ /**
+ * Sets the unique identifier of this widget. This is used to create
+ * the dynamic function names in the external interface calls.
+ * @param String p
+ */
+ public function set pid(p:String):void {
+ if(_pid == null) {
+ _pid = p;
+ init();
+ }
+ }
+
+ /**
+ * Set the background color of the coverflow
+ * @param String gradientStart
+ * @param String gradientEnd
+ */
+ public function setBackgroundColor(gradientStart:String, gradientEnd:String):void {
+ Application.application.setStyle('backgroundGradientColors', [gradientStart, gradientEnd]);
+ }
+
+ /**
+ * Make sure the scrollbar is up-to-date, both in size and position wise
+ */
+ private function invalidateScrollbar():void {
+ _scrollbar.width = unscaledWidth;
+ _scrollbar.y = unscaledHeight-_scrollbar.getExplicitOrMeasuredHeight()/2;
+ _scrollbar.maxScrollPosition = coverCount-1;
+ _scrollbar.scrollPosition = _selected;
+ _scrollbar.pageSize = 1;
+ _scrollbar.invalidateDisplayList();
+ }
+
+ /**
+ * Change the visibility status of the scrollbar
+ * @param String visibility
+ */
+ public function toggleScrollbarVisibility(visibility:String):void {
+ // Input is a string, because javascript can call directly on this function
+ if(visibility == "false")
+ _scrollbar.visible = false;
+ else
+ _scrollbar.visible = true;
+ }
+
+ /**
+ * Animate the state changes
+ */
+ private function animateChange():void {
+ // If there already is an animation in process, stop it (jump to the end) and start the new one.
+ if(_animation != null && _animation.isPlaying)
+ _animation.end();
+
+ // Set up a new animation. We want the "current" value go to the "_selected" value
+ _animation = new AnimateProperty(this);
+ _animation.property = "current";
+ _animation.toValue = _selected;
+ _animation.target = this;
+
+ // What is the duration of the animation? We don't want the animation to go too fast or too slow.
+ // An animation where the selected cover is changed with only one position should be relatively
+ // slow, so that we actually can se an animation. Therefore we've set a minimum length of the
+ // animation to 400 ms. If we jump over several covers, then we want the animation to be a
+ // bit longer, so that the animation would be smoother. Therefore we reserve 200ms between every
+ // cover change. Select which ever is bigger, 400ms or difference between current and selected
+ // cover * 200ms.
+ var duration:int = Math.max(400,Math.abs(Math.ceil(_current)-_selected)*200);
+
+ // If we do long jumps (for example by using the slider), we don't want the animation to go
+ // too long. Therefore we're setting a maximum length for the animation, in this case 2 seconds.
+ duration = Math.min(2000,duration);
+ _animation.duration = duration;
+
+ // We don't want the animation to be linear, we want it to slow down in the end
+ _animation.easingFunction = mx.effects.easing.Quadratic.easeOut;
+
+ // Start the animation
+ _animation.play();
+ }
+
+ }
+
+
+}
+ \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/flex/EventHandler.as b/src/com/vaadin/demo/coverflow/gwt/flex/EventHandler.as
new file mode 100644
index 0000000000..f9d25be24d
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/flex/EventHandler.as
@@ -0,0 +1,16 @@
+package {
+ import flash.events.EventDispatcher;
+ import flash.events.Event;
+
+ /**
+ * This is a simple class created for event handling. Basically it just
+ * dispatches some custom events related to state changes within the coverflow.
+ */
+ public class EventHandler extends EventDispatcher {
+ // Events
+ public static var DATA_CHANGED:String = "data_changed";
+ public static var CURRENT_CHANGED:String = "current_changed";
+
+
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/flex/coverflowflash.mxml b/src/com/vaadin/demo/coverflow/gwt/flex/coverflowflash.mxml
new file mode 100644
index 0000000000..612e8ba52f
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/flex/coverflowflash.mxml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<mx:Application
+ xmlns:mx="http://www.adobe.com/2006/mxml"
+ horizontalAlign="center" verticalAlign="middle"
+ creationComplete="{ init(); }"
+ xmlns:custom="*"
+ paddingLeft="0"
+ paddingTop="10"
+ paddingBottom="0"
+ paddingRight="0"
+ >
+
+ <mx:Script>
+ <![CDATA[
+ import mx.controls.Alert;
+
+ private var coverflow:Coverflow = new Coverflow();
+
+ private function init():void {
+ coverflow.setBackgroundColor(Application.application.parameters.bgS, Application.application.parameters.bgE);
+ coverflow.toggleScrollbarVisibility(Application.application.parameters.sbVis);
+ coverflow.pid = Application.application.parameters.pid;
+
+ container.addChild(coverflow);
+
+ }
+
+ ]]>
+ </mx:Script>
+
+ <mx:Box width="100%" height="100%" id="container" />
+</mx:Application>
+
diff --git a/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/DistortImage.as b/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/DistortImage.as
new file mode 100644
index 0000000000..101e9e217c
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/DistortImage.as
@@ -0,0 +1,306 @@
+/*
+# ***** BEGIN LICENSE BLOCK *****
+Copyright the original author or authors.
+Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (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.mozilla.org/MPL/MPL-1.1.html
+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.
+
+# ***** END LICENSE BLOCK *****
+*/
+
+
+/*
+****************************
+* From a first idea and first implementation of Andre Michelle www.andre-michelle.com
+* @version 2.0
+* @author Thomas Pfeiffer - kiroukou - http://www.thomas-pfeiffer.info
+* @author Richard Lester - RichL
+* @author Didier Brun - foxy - http://www.foxaweb.com
+* @author Alex Uhlmann
+* @website: http://sandy.media-box.net
+* @description: Tesselate a movieclip into several triangles to allow free transform distorsion.
+*/
+package sandy.util
+{
+ import flash.display.BitmapData;
+ import flash.display.DisplayObject;
+ import flash.display.Shape;
+ import flash.display.Sprite;
+ import flash.geom.Matrix;
+ import flash.geom.Rectangle;
+
+ public class DistortImage
+ {
+ public var smooth : Boolean;
+ // -- texture to distort
+ public var texture:BitmapData;
+ // -- container Sprite or Shape : the display object containing the distorted picture drawn via graphics.
+
+ private var _container:Object;
+ public function get container() : Object
+ {
+ return _container;
+ }
+
+ public function set container( value : Object ) : void
+ {
+ if( ( value is Shape ) || ( value is Sprite ) )
+ {
+ _container = value;
+ }
+ else
+ {
+ throw new Error('container must be flash.display.Shape or flash.display.Sprite');
+ }
+ }
+
+ // -- target Object : either a BitmapData or a sprite
+ public var target:Object;
+ // -- arrays of differents datas types
+ public var points:Array;
+
+ /////////////////////////
+ /// PRIVATE PROPERTIES //
+ /////////////////////////
+ private var offsetRect:Rectangle;
+ private var _w:Number;
+ private var _h:Number;
+ private var _xMin:Number;
+ private var _xMax:Number;
+ private var _yMin:Number
+ private var _yMax:Number;
+ // -- picture segmentation properties
+ private var _hseg:Number;
+ private var _vseg:Number;
+ private var _hsLen:Number;
+ private var _vsLen:Number;
+ private var _tri:Array;
+ private var _aMcs:Array;
+
+ public function DistortImage()
+ {
+ smooth = true;
+ }
+
+ /*
+ * @param vseg Number : the vertical precision
+ * @param hseg Number : the horizontal precision
+ * @param offsetRect Rectangle : optional, the real bounds to use.
+ * @throws: An error if target property isn't a BitmapData or a DisplayObject
+ */
+ public function initialize( vseg: Number, hseg: Number, offsetRect: Rectangle = null ) : void
+ {
+ if( target is BitmapData )
+ {
+ texture = target as BitmapData;
+ _w = texture.width;
+ _h = texture.height;
+ }
+ else if( target is DisplayObject )
+ {
+ renderVector( offsetRect );
+ }
+ else
+ {
+ throw new Error('target must be flash.display.BitmapData or flash.display.DisplayObject');
+ }
+ _vseg = vseg || 0;
+ _hseg = hseg || 0;
+
+ // --
+ _aMcs = new Array();
+ points = new Array();
+ _tri = new Array();
+ // --
+ __init();
+ }
+
+ public function render() : void
+ {
+ __render();
+ }
+
+ /**
+ * setTransform
+ *
+ * @param x0 Number the horizontal coordinate of the first point
+ * @param y0 Number the vertical coordinate of the first point
+ * @param x1 Number the horizontal coordinate of the second point
+ * @param y1 Number the vertical coordinate of the second point
+ * @param x2 Number the horizontal coordinate of the third point
+ * @param y2 Number the vertical coordinate of the third point
+ * @param x3 Number the horizontal coordinate of the fourth point
+ * @param y3 Number the vertical coordinate of the fourth point
+ *
+ * @description : Distort the bitmap to adjust it to those points.
+ */
+ public function setTransform( x0:Number , y0:Number ,
+ x1:Number , y1:Number ,
+ x2:Number , y2:Number ,
+ x3:Number , y3:Number ): void
+ {
+ var w:Number = _w;
+ var h:Number = _h;
+ var dx30:Number = x3 - x0;
+ var dy30:Number = y3 - y0;
+ var dx21:Number = x2 - x1;
+ var dy21:Number = y2 - y1;
+ var l:int = points.length;
+ while( --l > -1 )
+ {
+ var point:SandyPoint = points[ l ];
+ var gx:Number = ( point.x - _xMin ) / w;
+ var gy:Number = ( point.y - _yMin ) / h;
+ var bx:Number = x0 + gy * ( dx30 );
+ var by:Number = y0 + gy * ( dy30 );
+
+ point.sx = bx + gx * ( ( x1 + gy * ( dx21 ) ) - bx );
+ point.sy = by + gx * ( ( y1 + gy * ( dy21 ) ) - by );
+ }
+ __render();
+ }
+
+
+
+ /////////////////////////
+ /// PRIVATE METHODS ///
+ /////////////////////////
+
+ private function renderVector( offsetRect: Rectangle = null ) : void
+ {
+ var vector : DisplayObject = target as DisplayObject;
+ if( offsetRect != null )
+ {
+ texture = new BitmapData( offsetRect.width , offsetRect.height, true, 0x00000000 );
+ }
+ else
+ {
+ texture = new BitmapData( vector.width , vector.height, true, 0x00000000 );
+ offsetRect = new Rectangle( 0, 0, texture.width, texture.height );
+ }
+
+ var m : Matrix = new Matrix();
+ m.translate( offsetRect.x * -1, offsetRect.y * -1 );
+ texture.draw( vector, m );
+ container.transform.matrix.translate( vector.transform.matrix.tx, vector.transform.matrix.ty );
+ _w = offsetRect.width;
+ _h = offsetRect.height;
+ }
+
+ private function __init(): void
+ {
+ points = new Array();
+ _tri = new Array();
+ var ix:int, iy:int;
+ var w2: Number = _w / 2;
+ var h2: Number = _h / 2;
+ _xMin = _yMin = 0;
+ _xMax = _w; _yMax = _h;
+ _hsLen = _w / ( _hseg + 1 );
+ _vsLen = _h / ( _vseg + 1 );
+ var x:Number, y:Number;
+ var p0:SandyPoint, p1:SandyPoint, p2:SandyPoint;
+
+ // -- we create the points
+ for ( ix = 0 ; ix < _hseg + 2 ; ix++ )
+ {
+ for ( iy = 0 ; iy < _vseg + 2 ; iy++ )
+ {
+ x = ix * _hsLen;
+ y = iy * _vsLen;
+ points.push( new SandyPoint( x, y, x, y ) );
+ }
+ }
+ // -- we create the triangles
+ for ( ix = 0 ; ix < _vseg + 1 ; ix++ )
+ {
+ for ( iy = 0 ; iy < _hseg + 1 ; iy++ )
+ {
+ p0 = points[ iy + ix * ( _hseg + 2 ) ];
+ p1 = points[ iy + ix * ( _hseg + 2 ) + 1 ];
+ p2 = points[ iy + ( ix + 1 ) * ( _hseg + 2 ) ];
+ __addTriangle( p0, p1, p2 );
+ // --
+ p0 = points[ iy + ( ix + 1 ) * ( _vseg + 2 ) + 1 ];
+ p1 = points[ iy + ( ix + 1 ) * ( _vseg + 2 ) ];
+ p2 = points[ iy + ix * ( _vseg + 2 ) + 1 ];
+ __addTriangle( p0, p1, p2 );
+ }
+ }
+ }
+
+ private function __addTriangle( p0:SandyPoint, p1:SandyPoint, p2:SandyPoint ):void
+ {
+ var u0:Number, v0:Number, u1:Number, v1:Number, u2:Number, v2:Number;
+ var tMat:Matrix = new Matrix();
+ // --
+ u0 = p0.x; v0 = p0.y;
+ u1 = p1.x; v1 = p1.y;
+ u2 = p2.x; v2 = p2.y;
+ tMat.tx = -v0*(_w / (v1 - v0));
+ tMat.ty = -u0*(_h / (u2 - u0));
+ tMat.a = tMat.d = 0;
+ tMat.b = _h / (u2 - u0);
+ tMat.c = _w / (v1 - v0);
+ // --
+ _tri.push( new Triangle( p0, p1, p2, tMat ) );
+ }
+
+ private function __render(): void
+ {
+ var vertices: Array;
+ var p0:SandyPoint, p1:SandyPoint, p2:SandyPoint;
+ var x0:Number, y0:Number;
+ var ih:Number = 1/_h, iw:Number = 1/_w;
+ var c:Object = container; c.graphics.clear();
+ var a:Triangle;
+ var sM:Matrix = new Matrix();
+ var tM:Matrix = new Matrix();
+ //--
+ var l:int = _tri.length;
+ while( --l > -1 )
+ {
+ a = _tri[ l ];
+ p0 = a.p0;
+ p1 = a.p1;
+ p2 = a.p2;
+ tM = a.tMat;
+ // --
+ sM.a = ( p1.sx - ( x0 = p0.sx ) ) * iw;
+ sM.b = ( p1.sy - ( y0 = p0.sy ) ) * iw;
+ sM.c = ( p2.sx - x0 ) * ih;
+ sM.d = ( p2.sy - y0 ) * ih;
+ sM.tx = x0;
+ sM.ty = y0;
+ // --
+ sM = __concat( sM, tM );
+
+ c.graphics.beginBitmapFill( texture, sM, false, smooth );
+ c.graphics.moveTo( x0, y0 );
+ c.graphics.lineTo( p1.sx, p1.sy );
+ c.graphics.lineTo( p2.sx, p2.sy );
+ c.graphics.endFill();
+ }
+ }
+
+ private function __concat( m1:Matrix, m2:Matrix ):Matrix
+ {
+ //Relies on the original triangles being right angled with p0 being the right angle.
+ //Therefore a = d = zero (before and after invert)
+ var mat : Matrix = new Matrix();
+ mat.a = m1.c * m2.b;
+ mat.b = m1.d * m2.b;
+ mat.c = m1.a * m2.c;
+ mat.d = m1.b * m2.c;
+ mat.tx = m1.a * m2.tx + m1.c * m2.ty + m1.tx;
+ mat.ty = m1.b * m2.tx + m1.d * m2.ty + m1.ty;
+ return mat;
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/SandyPoint.as b/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/SandyPoint.as
new file mode 100644
index 0000000000..7d5c52ca0c
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/SandyPoint.as
@@ -0,0 +1,17 @@
+package sandy.util
+{
+ import flash.geom.Point;
+
+ public class SandyPoint extends Point
+ {
+ public var sx : Number;
+ public var sy : Number;
+
+ public function SandyPoint( x : Number, y : Number, sx : Number, sy : Number )
+ {
+ super( x, y );
+ this.sx = sx;
+ this.sy = sy;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/Triangle.as b/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/Triangle.as
new file mode 100644
index 0000000000..8f08fb6c76
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/flex/sandy/util/Triangle.as
@@ -0,0 +1,20 @@
+package sandy.util
+{
+ import flash.geom.Matrix;
+
+ public class Triangle
+ {
+ public var p0 : SandyPoint;
+ public var p1 : SandyPoint;
+ public var p2 : SandyPoint;
+ public var tMat : Matrix;
+
+ public function Triangle( p0 : SandyPoint, p1 : SandyPoint, p2 : SandyPoint, tMat : Matrix )
+ {
+ this.p0 = p0;
+ this.p1 = p1
+ this.p2 = p2;
+ this.tMat = tMat;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/public/coverflowflash.swf b/src/com/vaadin/demo/coverflow/gwt/public/coverflowflash.swf
new file mode 100644
index 0000000000..f3c75f4fe3
--- /dev/null
+++ b/src/com/vaadin/demo/coverflow/gwt/public/coverflowflash.swf
Binary files differ
diff --git a/src/com/vaadin/demo/featurebrowser/AccordionExample.java b/src/com/vaadin/demo/featurebrowser/AccordionExample.java
new file mode 100644
index 0000000000..8894f011e3
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/AccordionExample.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.ui.Accordion;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * Accordion is a derivative of TabSheet, a vertical tabbed layout that places
+ * the tab contents between the vertical tabs.
+ */
+public class AccordionExample extends CustomComponent {
+ public AccordionExample() {
+ // Create a new accordion
+ final Accordion accordion = new Accordion();
+ setCompositionRoot(accordion);
+
+ // Add a few tabs to the accordion.
+ for (int i = 0; i < 5; i++) {
+ // Create a root component for a accordion tab
+ VerticalLayout layout = new VerticalLayout();
+ accordion.addComponent(layout);
+
+ // The accordion tab label is taken from the caption of the root
+ // component. Notice that layouts can have a caption too.
+ layout.setCaption("Tab " + (i + 1));
+
+ // Add some components in each accordion tab
+ Label label = new Label("These are the contents of Tab " + (i + 1)
+ + ".");
+ layout.addComponent(label);
+
+ TextField textfield = new TextField("Some text field");
+ layout.addComponent(textfield);
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/ButtonExample.java b/src/com/vaadin/demo/featurebrowser/ButtonExample.java
new file mode 100644
index 0000000000..66a22ad657
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/ButtonExample.java
@@ -0,0 +1,139 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * Shows a few variations of Buttons and Links.
+ *
+ * @author IT Mill Ltd.
+ */
+public class ButtonExample extends CustomComponent implements
+ Button.ClickListener {
+
+ public ButtonExample() {
+
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ final Panel basic = new Panel("Basic buttons");
+ basic.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(basic);
+
+ final Panel bells = new Panel("w/ bells & whistles");
+ bells.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(bells);
+
+ Button b = new Button("Basic button");
+ b.addListener(this);
+ basic.addComponent(b);
+
+ b = new Button("Button w/ icon + tooltip");
+ b.addListener(this);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("This button does nothing, fast");
+ bells.addComponent(b);
+
+ b = new CheckBox("CheckBox - a switch-button");
+ b.setImmediate(true); // checkboxes are not immediate by default
+ b.addListener(this);
+ basic.addComponent(b);
+
+ b = new CheckBox("CheckBox w/ icon + tooltip");
+ b.setImmediate(true); // checkboxes are not immediate by default
+ b.addListener(this);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("This is a CheckBox");
+ bells.addComponent(b);
+
+ b = new Button("Link-style button");
+ b.addListener(this);
+ b.setStyleName(Button.STYLE_LINK);
+ basic.addComponent(b);
+
+ b = new Button("Link button w/ icon + tooltip");
+ b.addListener(this);
+ b.setStyleName(Button.STYLE_LINK);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("Link-style, icon+tootip, no caption");
+ bells.addComponent(b);
+
+ b = new Button();
+ b.addListener(this);
+ b.setStyleName(Button.STYLE_LINK);
+ b.setIcon(new ThemeResource("icons/ok.png"));
+ b.setDescription("Link-style, icon+tootip, no caption");
+ basic.addComponent(b);
+
+ final Panel links = new Panel("Links");
+ links.setStyleName(Panel.STYLE_LIGHT);
+ main.addComponent(links);
+ final Label desc = new Label(
+ "The main difference between a Link and"
+ + " a link-styled Button is that the Link works client-"
+ + " side, whereas the Button works server side.<br/> This means"
+ + " that the Button triggers some event on the server,"
+ + " while the Link is a normal web-link. <br/><br/>Note that for"
+ + " opening new windows, the Link might be a safer "
+ + " choice, since popup-blockers might interfer with "
+ + " server-initiated window opening.");
+ desc.setContentMode(Label.CONTENT_XHTML);
+ links.addComponent(desc);
+ Link l = new Link("IT Mill home", new ExternalResource(
+ "http://www.itmill.com"));
+ l.setDescription("Link without target name, opens in this window");
+ links.addComponent(l);
+
+ l = new Link("IT Mill home (new window)", new ExternalResource(
+ "http://www.itmill.com"));
+ l.setTargetName("_blank");
+ l.setDescription("Link with target name, opens in new window");
+ links.addComponent(l);
+
+ l = new Link("IT Mill home (new window, less decor)",
+ new ExternalResource("http://www.itmill.com"));
+ l.setTargetName("_blank");
+ l.setTargetBorder(Link.TARGET_BORDER_MINIMAL);
+ l.setTargetName("_blank");
+ l
+ .setDescription("Link with target name and BORDER_MINIMAL, opens in new window with less decor");
+ links.addComponent(l);
+
+ l = new Link("IT Mill home (new 200x200 window, no decor, icon)",
+ new ExternalResource("http://www.itmill.com"), "_blank", 200,
+ 200, Link.TARGET_BORDER_NONE);
+ l.setTargetName("_blank");
+ l
+ .setDescription("Link with target name and BORDER_NONE, opens in new window with no decor");
+ l.setIcon(new ThemeResource("icons/ok.png"));
+ links.addComponent(l);
+
+ }
+
+ public void buttonClick(ClickEvent event) {
+ final Button b = event.getButton();
+ getWindow().showNotification(
+ "Clicked"
+ + (b instanceof CheckBox ? ", value: "
+ + event.getButton().getValue() : ""));
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/ClientCachingExample.java b/src/com/vaadin/demo/featurebrowser/ClientCachingExample.java
new file mode 100644
index 0000000000..4f8cad2448
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/ClientCachingExample.java
@@ -0,0 +1,71 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * This example is a (simple) demonstration of client-side caching. The content
+ * in one tab is intentionally made very slow to produce server-side. When the
+ * user changes to this tab for the first time, there will be a 3 second wait
+ * before the content shows up, but the second time it shows up immediately
+ * since the content has not changed and is cached client-side.
+ *
+ * @author IT Mill Ltd.
+ */
+public class ClientCachingExample extends CustomComponent {
+
+ private static final String msg = "This example is a (simple) demonstration of client-side caching."
+ + " The content in one tab is intentionally made very slow to"
+ + " 'produce' server-side. When you changes to this tab for the"
+ + " first time, there will be a 3 second wait before the content"
+ + " shows up, but the second time it shows up immediately since the"
+ + " content has not changed and is cached client-side.";
+
+ public ClientCachingExample() {
+
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ main.addComponent(new Label(msg));
+
+ final TabSheet ts = new TabSheet();
+ main.addComponent(ts);
+
+ Layout layout = new VerticalLayout();
+ layout.setMargin(true);
+ Label l = new Label("This is a normal label, quick to render.");
+ l.setCaption("A normal label");
+ layout.addComponent(l);
+
+ ts.addTab(layout, "Normal", null);
+
+ layout = new VerticalLayout();
+ layout.setMargin(true);
+ l = new Label("Slow label - until cached client side.") {
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ try {
+ Thread.sleep(3000);
+ } catch (final Exception e) {
+ // IGNORED
+ }
+ super.paintContent(target);
+ }
+
+ };
+ l.setCaption("A slow label");
+ layout.addComponent(l);
+ ts.addTab(layout, "Slow", null);
+
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/ComboBoxExample.java b/src/com/vaadin/demo/featurebrowser/ComboBoxExample.java
new file mode 100644
index 0000000000..a28d16e597
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/ComboBoxExample.java
@@ -0,0 +1,70 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import java.util.Random;
+
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.AbstractSelect.Filtering;
+
+/**
+ *
+ */
+public class ComboBoxExample extends CustomComponent {
+
+ private static final String[] firstnames = new String[] { "John", "Mary",
+ "Joe", "Sarah", "Jeff", "Jane", "Peter", "Marc", "Robert", "Paula",
+ "Lenny", "Kenny", "Nathan", "Nicole", "Laura", "Jos", "Josie",
+ "Linus" };
+
+ private static final String[] lastnames = new String[] { "Torvalds",
+ "Smith", "Adams", "Black", "Wilson", "Richards", "Thompson",
+ "McGoff", "Halas", "Jones", "Beck", "Sheridan", "Picard", "Hill",
+ "Fielding", "Einstein" };
+
+ public ComboBoxExample() {
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ // starts-with filter
+ final ComboBox s1 = new ComboBox("Select with starts-with filter");
+ s1.setFilteringMode(Filtering.FILTERINGMODE_STARTSWITH);
+ s1.setWidth("20em");
+ Random r = new Random(5);
+ for (int i = 0; i < 105; i++) {
+ s1
+ .addItem(firstnames[(int) (r.nextDouble() * (firstnames.length - 1))]
+ + " "
+ + lastnames[(int) (r.nextDouble() * (lastnames.length - 1))]);
+ }
+ s1.setImmediate(true);
+ main.addComponent(s1);
+
+ // contains filter
+ final ComboBox s2 = new ComboBox("Select with contains filter");
+ s2.setFilteringMode(Filtering.FILTERINGMODE_CONTAINS);
+ s2.setWidth("20em");
+ for (int i = 0; i < 500; i++) {
+ s2
+ .addItem(firstnames[(int) (r.nextDouble() * (firstnames.length - 1))]
+ + " "
+ + lastnames[(int) (r.nextDouble() * (lastnames.length - 1))]);
+ }
+ s2.setImmediate(true);
+ main.addComponent(s2);
+
+ // initially empty
+ final ComboBox s3 = new ComboBox("Initially empty; enter your own");
+ s3.setWidth("20em");
+ s3.setImmediate(true);
+ s3.setNewItemsAllowed(true);
+ main.addComponent(s3);
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/EmbeddedBrowserExample.java b/src/com/vaadin/demo/featurebrowser/EmbeddedBrowserExample.java
new file mode 100644
index 0000000000..64800199c7
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/EmbeddedBrowserExample.java
@@ -0,0 +1,90 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.Select;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window.Notification;
+
+/**
+ * Demonstrates the use of Embedded and "suggesting" Select by creating a simple
+ * web-browser. Note: does not check for recursion.
+ *
+ * @author IT Mill Ltd.
+ * @see com.vaadin.ui.Window
+ */
+public class EmbeddedBrowserExample extends VerticalLayout implements
+ Select.ValueChangeListener {
+
+ // Default URL to open.
+ private static final String DEFAULT_URL = "http://www.itmill.com/index_itmill_toolkit.htm";
+
+ // The embedded page
+ Embedded emb = new Embedded();
+
+ public EmbeddedBrowserExample() {
+ this(new String[] { DEFAULT_URL,
+ "http://www.itmill.com/index_developers.htm",
+ "http://toolkit.itmill.com/demo/doc/api/",
+ "http://www.itmill.com/manual/index.html" });
+ }
+
+ public EmbeddedBrowserExample(String[] urls) {
+ setSizeFull();
+
+ // create the address combobox
+ final Select select = new Select();
+ // allow input
+ select.setNewItemsAllowed(true);
+ // no empty selection
+ select.setNullSelectionAllowed(false);
+ // no 'go' -button clicking necessary
+ select.setImmediate(true);
+ // add some pre-configured URLs
+ for (int i = 0; i < urls.length; i++) {
+ select.addItem(urls[i]);
+ }
+ // add to layout
+ addComponent(select);
+ // add listener and select initial URL
+ select.addListener(this);
+ select.setValue(urls[0]);
+
+ select.setWidth("100%");
+
+ // configure the embedded and add to layout
+ emb.setType(Embedded.TYPE_BROWSER);
+ emb.setSizeFull();
+ addComponent(emb);
+ // make the embedded as large as possible
+ setExpandRatio(emb, 1);
+
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ final String url = (String) event.getProperty().getValue();
+ if (url != null) {
+ try {
+ // the selected url has changed, let's go there
+ @SuppressWarnings("unused")
+ URL u = new URL(url);
+ emb.setSource(new ExternalResource(url));
+
+ } catch (MalformedURLException e) {
+ getWindow().showNotification("Invalid address",
+ e.getMessage() + " (example: http://www.itmill.com)",
+ Notification.TYPE_WARNING_MESSAGE);
+ }
+
+ }
+
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/FeatureBrowser.java b/src/com/vaadin/demo/featurebrowser/FeatureBrowser.java
new file mode 100644
index 0000000000..5a583f3724
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/FeatureBrowser.java
@@ -0,0 +1,383 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Select;
+import com.vaadin.ui.SplitPanel;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ *
+ * @author IT Mill Ltd.
+ * @see com.vaadin.ui.Window
+ */
+public class FeatureBrowser extends com.vaadin.Application implements
+ Select.ValueChangeListener {
+
+ // Property IDs
+ private static final Object PROPERTY_ID_CATEGORY = "Category";
+ private static final Object PROPERTY_ID_NAME = "Name";
+ private static final Object PROPERTY_ID_DESC = "Description";
+ private static final Object PROPERTY_ID_CLASS = "Class";
+ private static final Object PROPERTY_ID_VIEWED = "Viewed";
+
+ // Global components
+ private Tree tree;
+ private Table table;
+ private TabSheet ts;
+
+ // Example "cache"
+ private final HashMap exampleInstances = new HashMap();
+ private String section;
+
+ // List of examples
+ private static final Object[][] demos = new Object[][] {
+ // Category, Name, Desc, Class, Viewed
+ // Getting started: Labels
+ { "Getting started", "Labels", "Some variations of Labels",
+ LabelExample.class },
+ // Getting started: Buttons
+ { "Getting started", "Buttons and links",
+ "Various Buttons and Links", ButtonExample.class },
+ // Getting started: Fields
+ { "Getting started", "Basic value input",
+ "TextFields, DateFields, and such", ValueInputExample.class },
+ //
+ { "Getting started", "RichText", "Rich text editing",
+ RichTextExample.class },
+ // Getting started: Selects
+ { "Getting started", "Choices, choices",
+ "Some variations of simple selects", SelectExample.class },
+ // Layouts
+ { "Layouts", "Basic layouts", "Laying out components",
+ LayoutExample.class },
+ // Layouts
+ { "Layouts", "Accordion", "Play the Accordion!",
+ AccordionExample.class },
+ // Wrangling data: ComboBox
+ { "Wrangling data", "ComboBox", "ComboBox - the swiss army select",
+ ComboBoxExample.class },
+ // Wrangling data: Table
+ {
+ "Wrangling data",
+ "Table (\"grid\")",
+ "Table with bells, whistles, editmode and actions (contextmenu)",
+ TableExample.class },
+ // Wrangling data: Form
+ { "Wrangling data", "Form", "Every application needs forms",
+ FormExample.class },
+ // Wrangling data: Tree
+ { "Wrangling data", "Tree", "A hierarchy of things",
+ TreeExample.class },
+ // Misc: Notifications
+ { "Misc", "Notifications", "Notifications can improve usability",
+ NotificationExample.class },
+ // Misc: Caching
+ { "Misc", "Client caching", "Demonstrating of client-side caching",
+ ClientCachingExample.class },
+ // Misc: Embedded
+ { "Misc", "Embedding",
+ "Embedding resources - another site in this case",
+ EmbeddedBrowserExample.class },
+ // Windowing
+ { "Misc", "Windowing", "About windowing", WindowingExample.class },
+ // JavaScript API
+ { "Misc", "JavaScript API",
+ "JavaScript to IT Mill Toolkit communication",
+ JavaScriptAPIExample.class },
+ // END
+ };
+
+ @Override
+ public void init() {
+
+ // Need to set a theme for ThemeResources to work
+ setTheme("example");
+
+ // Create new window for the application and give the window a visible.
+ final Window main = new Window("IT Mill Toolkit 5");
+ // set as main window
+ setMainWindow(main);
+
+ final SplitPanel split = new SplitPanel(
+ SplitPanel.ORIENTATION_HORIZONTAL);
+ split.setSplitPosition(200, SplitPanel.UNITS_PIXELS);
+ main.setLayout(split);
+
+ final HashMap sectionIds = new HashMap();
+ final HierarchicalContainer container = createContainer();
+ final Object rootId = container.addItem();
+ Item item = container.getItem(rootId);
+ Property p = item.getItemProperty(PROPERTY_ID_NAME);
+ p.setValue("All examples");
+ for (int i = 0; i < demos.length; i++) {
+ final Object[] demo = demos[i];
+ final String section = (String) demo[0];
+ Object sectionId;
+ if (sectionIds.containsKey(section)) {
+ sectionId = sectionIds.get(section);
+ } else {
+ sectionId = container.addItem();
+ sectionIds.put(section, sectionId);
+ container.setParent(sectionId, rootId);
+ item = container.getItem(sectionId);
+ p = item.getItemProperty(PROPERTY_ID_NAME);
+ p.setValue(section);
+ }
+ final Object id = container.addItem();
+ container.setParent(id, sectionId);
+ initItem(container.getItem(id), demo);
+
+ }
+
+ tree = new Tree();
+ tree.setDebugId("FeatureBrowser: Main Tree");
+ tree.setSelectable(true);
+ tree.setMultiSelect(false);
+ tree.setNullSelectionAllowed(false);
+ tree.setContainerDataSource(container);
+ tree.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+ tree.setItemCaptionPropertyId(PROPERTY_ID_NAME);
+ tree.addListener(this);
+ tree.setImmediate(true);
+ tree.expandItemsRecursively(rootId);
+ for (Iterator i = container.getItemIds().iterator(); i.hasNext();) {
+ Object id = i.next();
+ if (container.getChildren(id) == null) {
+ tree.setChildrenAllowed(id, false);
+ }
+ }
+
+ split.addComponent(tree);
+
+ final SplitPanel split2 = new SplitPanel();
+ split2.setSplitPosition(200, SplitPanel.UNITS_PIXELS);
+ split.addComponent(split2);
+
+ table = new Table();
+ table.setDebugId("FeatureBrowser: Main Table");
+ table.setSizeFull();
+ table.setColumnReorderingAllowed(true);
+ table.setColumnCollapsingAllowed(true);
+ table.setSelectable(true);
+ table.setMultiSelect(false);
+ table.setNullSelectionAllowed(false);
+ try {
+ table.setContainerDataSource((IndexedContainer) container.clone());
+ } catch (final Exception e) {
+ e.printStackTrace(System.err);
+ }
+ // Hide some columns
+ table.setVisibleColumns(new Object[] { PROPERTY_ID_CATEGORY,
+ PROPERTY_ID_NAME, PROPERTY_ID_DESC, PROPERTY_ID_VIEWED });
+ table.addListener(this);
+ table.setImmediate(true);
+ split2.addComponent(table);
+
+ final VerticalLayout exp = new VerticalLayout();
+ exp.setSizeFull();
+ exp.setMargin(true);
+ split2.addComponent(exp);
+
+ final HorizontalLayout wbLayout = new HorizontalLayout();
+ Button b = new Button("Open in sub-window", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Component component = (Component) ts.getComponentIterator()
+ .next();
+ String caption = ts.getTabCaption(component);
+ try {
+ component = component.getClass().newInstance();
+ } catch (Exception e) {
+ // Could not create
+ return;
+ }
+ Window w = new Window(caption);
+ w.setWidth("640px");
+ if (Layout.class.isAssignableFrom(component.getClass())) {
+ w.setLayout((Layout) component);
+ } else {
+ // w.getLayout().getSize().setSizeFull();
+ w.addComponent(component);
+ }
+ getMainWindow().addWindow(w);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ wbLayout.addComponent(b);
+ b = new Button("Open in native window", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Component component = (Component) ts.getComponentIterator()
+ .next();
+ final String caption = ts.getTabCaption(component);
+ Window w = getWindow(caption);
+ if (w == null) {
+ try {
+ component = component.getClass().newInstance();
+ } catch (final Exception e) {
+ // Could not create
+ return;
+ }
+ w = new Window(caption);
+ w.setName(caption);
+ if (Layout.class.isAssignableFrom(component.getClass())) {
+ w.setLayout((Layout) component);
+ } else {
+ // w.getLayout().getSize().setSizeFull();
+ w.addComponent(component);
+ }
+ addWindow(w);
+ }
+ getMainWindow().open(new ExternalResource(w.getURL()), caption);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ wbLayout.addComponent(b);
+
+ exp.addComponent(wbLayout);
+ exp.setComponentAlignment(wbLayout, Alignment.TOP_RIGHT);
+
+ ts = new TabSheet();
+ ts.setSizeFull();
+ ts.addTab(new Label(""), "Choose example", null);
+ exp.addComponent(ts);
+ exp.setExpandRatio(ts, 1);
+
+ final Label status = new Label(
+ "<a href=\"http://www.itmill.com/developers/\">Developer Area</a>"
+ + " | <a href=\"http://www.itmill.com/documentation/\">Documentation</a>");
+ status.setContentMode(Label.CONTENT_XHTML);
+ exp.addComponent(status);
+ exp.setComponentAlignment(status, Alignment.MIDDLE_RIGHT);
+
+ // select initial section ("All")
+ tree.setValue(rootId);
+
+ getMainWindow()
+ .showNotification(
+ "Welcome",
+ "Choose an example to begin.<br/><br/>And remember to experiment!",
+ Window.Notification.TYPE_TRAY_NOTIFICATION);
+ }
+
+ private void initItem(Item item, Object[] data) {
+ int p = 0;
+ Property prop = item.getItemProperty(PROPERTY_ID_CATEGORY);
+ prop.setValue(data[p++]);
+ prop = item.getItemProperty(PROPERTY_ID_NAME);
+ prop.setValue(data[p++]);
+ prop = item.getItemProperty(PROPERTY_ID_DESC);
+ prop.setValue(data[p++]);
+ prop = item.getItemProperty(PROPERTY_ID_CLASS);
+ prop.setValue(data[p++]);
+ }
+
+ private HierarchicalContainer createContainer() {
+ final HierarchicalContainer c = new HierarchicalContainer();
+ c.addContainerProperty(PROPERTY_ID_CATEGORY, String.class, null);
+ c.addContainerProperty(PROPERTY_ID_NAME, String.class, "");
+ c.addContainerProperty(PROPERTY_ID_DESC, String.class, "");
+ c.addContainerProperty(PROPERTY_ID_CLASS, Class.class, null);
+ c.addContainerProperty(PROPERTY_ID_VIEWED, Embedded.class, null);
+ return c;
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ if (event.getProperty() == tree) {
+ final Object id = tree.getValue();
+ if (id == null) {
+ return;
+ }
+ final Item item = tree.getItem(id);
+ //
+ String newSection;
+ if (tree.isRoot(id)) {
+ newSection = ""; // show all sections
+ } else if (tree.hasChildren(id)) {
+ newSection = (String) item.getItemProperty(PROPERTY_ID_NAME)
+ .getValue();
+ } else {
+ newSection = (String) item
+ .getItemProperty(PROPERTY_ID_CATEGORY).getValue();
+ }
+
+ table.setValue(null);
+ final IndexedContainer c = (IndexedContainer) table
+ .getContainerDataSource();
+
+ if (newSection != null && !newSection.equals(section)) {
+ c.removeAllContainerFilters();
+ c.addContainerFilter(PROPERTY_ID_CATEGORY, newSection, false,
+ true);
+ }
+ section = newSection;
+ if (!tree.hasChildren(id)) {
+ // Example, not section
+ // update table selection
+ table.setValue(id);
+ }
+
+ } else if (event.getProperty() == table) {
+ if (table.getValue() != null) {
+ table.removeListener(this);
+ tree.setValue(table.getValue());
+ table.addListener(this);
+ final Item item = table.getItem(table.getValue());
+ final Class c = (Class) item.getItemProperty(PROPERTY_ID_CLASS)
+ .getValue();
+ final Component component = getComponent(c);
+ if (component != null) {
+ final String caption = (String) item.getItemProperty(
+ PROPERTY_ID_NAME).getValue();
+ ts.removeAllComponents();
+ ts.addTab(component, caption, null);
+ }
+ // update "viewed" state
+ final Property p = item.getItemProperty(PROPERTY_ID_VIEWED);
+ if (p.getValue() == null) {
+ p.setValue(new Embedded("", new ThemeResource(
+ "icons/ok.png")));
+ }
+ table.requestRepaint();
+ }
+ }
+
+ }
+
+ private Component getComponent(Class componentClass) {
+ if (!exampleInstances.containsKey(componentClass)) {
+ try {
+ final Component c = (Component) componentClass.newInstance();
+ exampleInstances.put(componentClass, c);
+ } catch (final Exception e) {
+ return null;
+ }
+ }
+ return (Component) exampleInstances.get(componentClass);
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/FormExample.java b/src/com/vaadin/demo/featurebrowser/FormExample.java
new file mode 100644
index 0000000000..182e6346d1
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/FormExample.java
@@ -0,0 +1,229 @@
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Validator;
+import com.vaadin.data.Validator.InvalidValueException;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.ui.BaseFieldFactory;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.Form;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+/**
+ * This example demonstrates the most important features of the Form component:
+ * binding Form to a JavaBean so that form fields are automatically generated
+ * from the bean properties, creation of custom field editors using a
+ * FieldFactory, customizing the form without FieldFactory, buffering
+ * (commit/discard) and validation. Please note that the example is quite a bit
+ * more complex than real use, as it tries to demonstrate more features than
+ * needed in general case.
+ */
+public class FormExample extends CustomComponent {
+
+ static final String cities[] = { "Amsterdam", "Berlin", "Helsinki",
+ "Hong Kong", "London", "Luxemburg", "New York", "Oslo", "Paris",
+ "Rome", "Stockholm", "Tokyo", "Turku" };
+
+ /** Compose the demo. */
+ public FormExample() {
+
+ // Example data model
+ final Address dataModel = new Address();
+ Button peekDataModelState = new Button("Show the data model state",
+ new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ dataModel.getAddressAsText());
+ }
+ });
+
+ // Example form
+ final AddressForm form = new AddressForm("Contact Information");
+ form.setDataSource(dataModel);
+ form
+ .setDescription("Please enter valid name and address. Fields marked with * are required. "
+ + "If you try to commit with invalid values, a form error message is displayed. "
+ + "(Address is required but failing to give it a value does not display an error.)");
+
+ // Layout the example
+ VerticalLayout root = new VerticalLayout();
+ root.setMargin(true);
+ root.setSpacing(true);
+ root.addComponent(form);
+ root.addComponent(peekDataModelState);
+ setCompositionRoot(root);
+ }
+
+ public static class AddressForm extends Form {
+ public AddressForm(String caption) {
+
+ setCaption(caption);
+
+ // Use custom field factory to modify the defaults on how the
+ // components are created
+ setFieldFactory(new MyFieldFactory());
+
+ // Add Commit and Discard controls to the form.
+
+ Button commit = new Button("Save", new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ try {
+ commit();
+ } catch (InvalidValueException e) {
+ // Failed to commit. The validation errors are
+ // automatically shown to the user.
+ }
+ }
+
+ });
+
+ Button discard = new Button("Reset", this, "discard");
+ HorizontalLayout footer = new HorizontalLayout();
+ footer.addComponent(commit);
+ footer.addComponent(discard);
+ setFooter(footer);
+ }
+
+ public void setDataSource(Address dataModel) {
+
+ // Set the form to edit given datamodel by converting pojo used as
+ // the datamodel to Item
+ setItemDataSource(new BeanItem(dataModel));
+
+ // Ensure that the fields are shown in correct order as the
+ // datamodel does not force any specific order.
+ setVisibleItemProperties(new String[] { "name", "streetAddress",
+ "postalCode", "city" });
+
+ // For examples sake, customize some of the form fields directly
+ // here. The alternative way is to use custom field factory as shown
+ // above.
+ getField("name").setRequired(true);
+ getField("name").setDescription("Please enter name");
+ getField("name").setRequiredError("Name is missing");
+ getField("streetAddress").setRequired(true); // No error message
+ getField("streetAddress").setDescription(
+ "Please enter street adderss.");
+ getField("postalCode").setRequired(true); // No error message
+ getField("postalCode").setDescription(
+ "Please enter postal code. Example: 12345.");
+ replaceWithSelect("city", cities, cities).setNewItemsAllowed(true);
+ getField("city")
+ .setDescription(
+ "Select city from list or type it. City field is not required.");
+
+ // Set the form to act immediately on user input. This is
+ // automatically transports data between the client and the server
+ // to do server-side validation.
+ setImmediate(true);
+
+ // Enable buffering so that commit() must be called for the form
+ // before input is written to the data. (Form input is not written
+ // immediately through to the underlying object.)
+ setWriteThrough(false);
+ }
+ }
+
+ /**
+ * This is example on how to customize field creation. Any kind of field
+ * components could be created on the fly.
+ */
+ static class MyFieldFactory extends BaseFieldFactory {
+
+ @Override
+ public Field createField(Item item, Object propertyId,
+ Component uiContext) {
+
+ Field field = super.createField(item, propertyId, uiContext);
+
+ if ("postalCode".equals(propertyId)) {
+ ((TextField) field).setColumns(5);
+ field.addValidator(new PostalCodeValidator());
+ }
+
+ return field;
+ }
+
+ }
+
+ /**
+ * This is an example of how to create a custom validator for automatic
+ * input validation.
+ */
+ static class PostalCodeValidator implements Validator {
+
+ public boolean isValid(Object value) {
+ if (value == null || !(value instanceof String)) {
+ return false;
+ }
+
+ return ((String) value).matches("[0-9]{5}");
+ }
+
+ public void validate(Object value) throws InvalidValueException {
+ if (!isValid(value)) {
+ throw new InvalidValueException(
+ "Postal code must be a five digit number.");
+ }
+ }
+ }
+
+ /**
+ * Contact information data model created as POJO. Note that in many cases
+ * it would be a good idea to implement Item -interface for the datamodel to
+ * make it directly bindable to form (without BeanItem wrapper)
+ */
+ public static class Address {
+ String name = "";
+ String streetAddress = "";
+ String postalCode = "";
+ String city;
+
+ public String getAddressAsText() {
+ return name + "\n" + streetAddress + "\n" + postalCode + " "
+ + (city == null ? "" : city);
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setStreetAddress(String address) {
+ streetAddress = address;
+ }
+
+ public String getStreetAddress() {
+ return streetAddress;
+ }
+
+ public void setPostalCode(String postalCode) {
+ this.postalCode = postalCode;
+ }
+
+ public String getPostalCode() {
+ return postalCode;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getCity() {
+ return city;
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/GeneratedColumnExample.java b/src/com/vaadin/demo/featurebrowser/GeneratedColumnExample.java
new file mode 100644
index 0000000000..e6a1edf088
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/GeneratedColumnExample.java
@@ -0,0 +1,556 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Vector;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Container.Indexed;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.ui.AbstractField;
+import com.vaadin.ui.BaseFieldFactory;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+/**
+ * This example demonstrates the use of generated columns in a table. Generated
+ * columns can be used for formatting values or calculating them from other
+ * columns (or properties of the items).
+ *
+ * For the data model, we use POJOs bound to a custom Container with BeanItem
+ * items.
+ *
+ * @author magi
+ */
+public class GeneratedColumnExample extends CustomComponent {
+ /**
+ * The business model: fill-up at a gas station.
+ */
+ public class FillUp {
+ Date date;
+ double quantity;
+ double total;
+
+ public FillUp() {
+ }
+
+ public FillUp(int day, int month, int year, double quantity,
+ double total) {
+ date = new GregorianCalendar(year, month - 1, day).getTime();
+ this.quantity = quantity;
+ this.total = total;
+ }
+
+ /** Calculates price per unit of quantity (€/l). */
+ public double price() {
+ if (quantity != 0.0) {
+ return total / quantity;
+ } else {
+ return 0.0;
+ }
+ }
+
+ /** Calculates average daily consumption between two fill-ups. */
+ public double dailyConsumption(FillUp other) {
+ double difference_ms = date.getTime() - other.date.getTime();
+ double days = difference_ms / 1000 / 3600 / 24;
+ if (days < 0.5) {
+ days = 1.0; // Avoid division by zero if two fill-ups on the
+ // same day.
+ }
+ return quantity / days;
+ }
+
+ /** Calculates average daily consumption between two fill-ups. */
+ public double dailyCost(FillUp other) {
+ return price() * dailyConsumption(other);
+ }
+
+ // Getters and setters
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public double getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(double quantity) {
+ this.quantity = quantity;
+ }
+
+ public double getTotal() {
+ return total;
+ }
+
+ public void setTotal(double total) {
+ this.total = total;
+ }
+ };
+
+ /**
+ * This is a custom container that allows adding BeanItems inside it. The
+ * BeanItem objects must be bound to an object. The item ID is an Integer
+ * from 0 to 99.
+ *
+ * Most of the interface methods are implemented with just dummy
+ * implementations, as they are not needed in this example.
+ */
+ public class MySimpleIndexedContainer implements Container, Indexed {
+ Vector items;
+ Object itemtemplate;
+
+ public MySimpleIndexedContainer(Object itemtemplate) {
+ this.itemtemplate = itemtemplate;
+ items = new Vector(); // Yeah this is just a test
+ }
+
+ public boolean addContainerProperty(Object propertyId, Class type,
+ Object defaultValue) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Item addItem(Object itemId) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object addItem() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * This addItem method is specific for this container and allows adding
+ * BeanItem objects. The BeanItems must be bound to MyBean objects.
+ */
+ public void addItem(BeanItem item) throws UnsupportedOperationException {
+ items.add(item);
+ }
+
+ public boolean containsId(Object itemId) {
+ if (itemId instanceof Integer) {
+ int pos = ((Integer) itemId).intValue();
+ if (pos >= 0 && pos < items.size()) {
+ return items.get(pos) != null;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * The Table will call this method to get the property objects for the
+ * columns. It uses the property objects to determine the data types of
+ * the columns.
+ */
+ public Property getContainerProperty(Object itemId, Object propertyId) {
+ if (itemId instanceof Integer) {
+ int pos = ((Integer) itemId).intValue();
+ if (pos >= 0 && pos < items.size()) {
+ Item item = (Item) items.get(pos);
+
+ // The BeanItem provides the property objects for the items.
+ return item.getItemProperty(propertyId);
+ }
+ }
+ return null;
+ }
+
+ /** Table calls this to get the column names. */
+ public Collection getContainerPropertyIds() {
+ Item item = new BeanItem(itemtemplate);
+
+ // The BeanItem knows how to get the property names from the bean.
+ return item.getItemPropertyIds();
+ }
+
+ public Item getItem(Object itemId) {
+ if (itemId instanceof Integer) {
+ int pos = ((Integer) itemId).intValue();
+ if (pos >= 0 && pos < items.size()) {
+ return (Item) items.get(pos);
+ }
+ }
+ return null;
+ }
+
+ public Collection getItemIds() {
+ Vector ids = new Vector(items.size());
+ for (int i = 0; i < items.size(); i++) {
+ ids.add(Integer.valueOf(i));
+ }
+ return ids;
+ }
+
+ public Class getType(Object propertyId) {
+ return BeanItem.class;
+ }
+
+ public boolean removeAllItems() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean removeContainerProperty(Object propertyId)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean removeItem(Object itemId)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ public int size() {
+ return items.size();
+ }
+
+ public Object addItemAt(int index) throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Item addItemAt(int index, Object newItemId)
+ throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Object getIdByIndex(int index) {
+ return Integer.valueOf(index);
+ }
+
+ public int indexOfId(Object itemId) {
+ return ((Integer) itemId).intValue();
+ }
+
+ public Object addItemAfter(Object previousItemId)
+ throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Item addItemAfter(Object previousItemId, Object newItemId)
+ throws UnsupportedOperationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Object firstItemId() {
+ return new Integer(0);
+ }
+
+ public boolean isFirstId(Object itemId) {
+ return ((Integer) itemId).intValue() == 0;
+ }
+
+ public boolean isLastId(Object itemId) {
+ return ((Integer) itemId).intValue() == (items.size() - 1);
+ }
+
+ public Object lastItemId() {
+ return new Integer(items.size() - 1);
+ }
+
+ public Object nextItemId(Object itemId) {
+ int pos = indexOfId(itemId);
+ if (pos >= items.size() - 1) {
+ return null;
+ }
+ return getIdByIndex(pos + 1);
+ }
+
+ public Object prevItemId(Object itemId) {
+ int pos = indexOfId(itemId);
+ if (pos <= 0) {
+ return null;
+ }
+ return getIdByIndex(pos - 1);
+ }
+ }
+
+ /** Formats the dates in a column containing Date objects. */
+ class DateColumnGenerator implements Table.ColumnGenerator {
+ /**
+ * Generates the cell containing the Date value. The column is
+ * irrelevant in this use case.
+ */
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Property prop = source.getItem(itemId).getItemProperty(columnId);
+ if (prop.getType().equals(Date.class)) {
+ Label label = new Label(String.format("%tF",
+ new Object[] { (Date) prop.getValue() }));
+ label.addStyleName("column-type-date");
+ return label;
+ }
+
+ return null;
+ }
+ }
+
+ /** Formats the value in a column containing Double objects. */
+ class ValueColumnGenerator implements Table.ColumnGenerator {
+ String format; /* Format string for the Double values. */
+
+ /** Creates double value column formatter with the given format string. */
+ public ValueColumnGenerator(String format) {
+ this.format = format;
+ }
+
+ /**
+ * Generates the cell containing the Double value. The column is
+ * irrelevant in this use case.
+ */
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Property prop = source.getItem(itemId).getItemProperty(columnId);
+ if (prop.getType().equals(Double.class)) {
+ Label label = new Label(String.format(format,
+ new Object[] { (Double) prop.getValue() }));
+
+ // Set styles for the column: one indicating that it's a value
+ // and a more
+ // specific one with the column name in it. This assumes that
+ // the column
+ // name is proper for CSS.
+ label.addStyleName("column-type-value");
+ label.addStyleName("column-" + (String) columnId);
+ return label;
+ }
+ return null;
+ }
+ }
+
+ /** Table column generator for calculating price column. */
+ class PriceColumnGenerator implements Table.ColumnGenerator {
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ // Retrieve the item.
+ BeanItem item = (BeanItem) source.getItem(itemId);
+
+ // Retrieves the underlying POJO from the item.
+ FillUp fillup = (FillUp) item.getBean();
+
+ // Do the business logic
+ double price = fillup.price();
+
+ // Create the generated component for displaying the calcucated
+ // value.
+ Label label = new Label(String.format("%1.2f €",
+ new Object[] { new Double(price) }));
+
+ // We set the style here. You can't use a CellStyleGenerator for
+ // generated columns.
+ label.addStyleName("column-price");
+ return label;
+ }
+ }
+
+ /** Table column generator for calculating consumption column. */
+ class ConsumptionColumnGenerator implements Table.ColumnGenerator {
+ /**
+ * Generates a cell containing value calculated from the item.
+ */
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Indexed indexedSource = (Indexed) source.getContainerDataSource();
+
+ // Can not calculate consumption for the first item.
+ if (indexedSource.isFirstId(itemId)) {
+ Label label = new Label("N/A");
+ label.addStyleName("column-consumption");
+ return label;
+ }
+
+ // Index of the previous item.
+ Object prevItemId = indexedSource.prevItemId(itemId);
+
+ // Retrieve the POJOs.
+ FillUp fillup = (FillUp) ((BeanItem) indexedSource.getItem(itemId))
+ .getBean();
+ FillUp prev = (FillUp) ((BeanItem) source.getItem(prevItemId))
+ .getBean();
+
+ // Do the business logic
+ return generateCell(fillup, prev);
+ }
+
+ public Component generateCell(FillUp fillup, FillUp prev) {
+ double consumption = fillup.dailyConsumption(prev);
+
+ // Generate the component for displaying the calculated value.
+ Label label = new Label(String.format("%3.2f l",
+ new Object[] { new Double(consumption) }));
+
+ // We set the style here. You can't use a CellStyleGenerator for
+ // generated columns.
+ label.addStyleName("column-consumption");
+ return label;
+ }
+ }
+
+ /** Table column generator for calculating daily cost column. */
+ class DailyCostColumnGenerator extends ConsumptionColumnGenerator {
+ @Override
+ public Component generateCell(FillUp fillup, FillUp prev) {
+ double dailycost = fillup.dailyCost(prev);
+
+ // Generate the component for displaying the calculated value.
+ Label label = new Label(String.format("%3.2f €",
+ new Object[] { new Double(dailycost) }));
+
+ // We set the style here. You can't use a CellStyleGenerator for
+ // generated columns.
+ label.addStyleName("column-dailycost");
+ return label;
+ }
+ }
+
+ /**
+ * Custom field factory that sets the fields as immediate.
+ */
+ public class ImmediateFieldFactory extends BaseFieldFactory {
+ @Override
+ public Field createField(Class type, Component uiContext) {
+ // Let the BaseFieldFactory create the fields
+ Field field = super.createField(type, uiContext);
+
+ // ...and just set them as immediate
+ ((AbstractField) field).setImmediate(true);
+
+ return field;
+ }
+ }
+
+ public GeneratedColumnExample() {
+ final Table table = new Table();
+
+ // Define table columns. These include also the column for the generated
+ // column, because we want to set the column label to something
+ // different than the property ID.
+ table
+ .addContainerProperty("date", Date.class, null, "Date", null,
+ null);
+ table.addContainerProperty("quantity", Double.class, null,
+ "Quantity (l)", null, null);
+ table.addContainerProperty("price", Double.class, null, "Price (€/l)",
+ null, null);
+ table.addContainerProperty("total", Double.class, null, "Total (€)",
+ null, null);
+ table.addContainerProperty("consumption", Double.class, null,
+ "Consumption (l/day)", null, null);
+ table.addContainerProperty("dailycost", Double.class, null,
+ "Daily Cost (€/day)", null, null);
+
+ // Define the generated columns and their generators.
+ table.addGeneratedColumn("date", new DateColumnGenerator());
+ table
+ .addGeneratedColumn("quantity", new ValueColumnGenerator(
+ "%.2f l"));
+ table.addGeneratedColumn("price", new PriceColumnGenerator());
+ table.addGeneratedColumn("total", new ValueColumnGenerator("%.2f €"));
+ table.addGeneratedColumn("consumption",
+ new ConsumptionColumnGenerator());
+ table.addGeneratedColumn("dailycost", new DailyCostColumnGenerator());
+
+ // Create a data source and bind it to the table.
+ MySimpleIndexedContainer data = new MySimpleIndexedContainer(
+ new FillUp());
+ table.setContainerDataSource(data);
+
+ // Generated columns are automatically placed after property columns, so
+ // we have to set the order of the columns explicitly.
+ table.setVisibleColumns(new Object[] { "date", "quantity", "price",
+ "total", "consumption", "dailycost" });
+
+ // Add some data.
+ data.addItem(new BeanItem(new FillUp(19, 2, 2005, 44.96, 51.21)));
+ data.addItem(new BeanItem(new FillUp(30, 3, 2005, 44.91, 53.67)));
+ data.addItem(new BeanItem(new FillUp(20, 4, 2005, 42.96, 49.06)));
+ data.addItem(new BeanItem(new FillUp(23, 5, 2005, 47.37, 55.28)));
+ data.addItem(new BeanItem(new FillUp(6, 6, 2005, 35.34, 41.52)));
+ data.addItem(new BeanItem(new FillUp(30, 6, 2005, 16.07, 20.00)));
+ data.addItem(new BeanItem(new FillUp(2, 7, 2005, 36.40, 36.19)));
+ data.addItem(new BeanItem(new FillUp(6, 7, 2005, 39.17, 50.90)));
+ data.addItem(new BeanItem(new FillUp(27, 7, 2005, 43.43, 53.03)));
+ data.addItem(new BeanItem(new FillUp(17, 8, 2005, 20, 29.18)));
+ data.addItem(new BeanItem(new FillUp(30, 8, 2005, 46.06, 59.09)));
+ data.addItem(new BeanItem(new FillUp(22, 9, 2005, 46.11, 60.36)));
+ data.addItem(new BeanItem(new FillUp(14, 10, 2005, 41.51, 50.19)));
+ data.addItem(new BeanItem(new FillUp(12, 11, 2005, 35.24, 40.00)));
+ data.addItem(new BeanItem(new FillUp(28, 11, 2005, 45.26, 53.27)));
+
+ // Have a check box that allows the user to make the quantity
+ // and total columns editable.
+ final CheckBox editable = new CheckBox(
+ "Edit the input values - calculated columns are regenerated");
+ editable.setImmediate(true);
+ editable.addListener(new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ table.setEditable(editable.booleanValue());
+
+ // The columns may not be generated when we want to have them
+ // editable.
+ if (editable.booleanValue()) {
+ table.removeGeneratedColumn("quantity");
+ table.removeGeneratedColumn("total");
+ } else {
+ // In non-editable mode we want to show the formatted
+ // values.
+ table.addGeneratedColumn("quantity",
+ new ValueColumnGenerator("%.2f l"));
+ table.addGeneratedColumn("total", new ValueColumnGenerator(
+ "%.2f €"));
+ }
+ // The visible columns are affected by removal and addition of
+ // generated columns so we have to redefine them.
+ table.setVisibleColumns(new Object[] { "date", "quantity",
+ "price", "total", "consumption", "dailycost" });
+ }
+ });
+
+ // Use a custom field factory to set the edit fields as immediate.
+ // This is used when the table is in editable mode.
+ table.setFieldFactory(new ImmediateFieldFactory());
+
+ // Setting the table itself as immediate has no relevance in this
+ // example,
+ // because it is relevant only if the table is selectable and we want to
+ // get the selection changes immediately.
+ table.setImmediate(true);
+
+ table.setHeight("300px");
+
+ VerticalLayout layout = new VerticalLayout();
+ layout.setMargin(true);
+ layout
+ .addComponent(new Label(
+ "Table with column generators that format and calculate cell values."));
+ layout.addComponent(table);
+ layout.addComponent(editable);
+ layout.addComponent(new Label(
+ "Columns displayed in blue are calculated from Quantity and Total. "
+ + "Others are simply formatted."));
+ layout.setExpandRatio(table, 1);
+ layout.setSizeUndefined();
+ setCompositionRoot(layout);
+ // setSizeFull();
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/JavaScriptAPIExample.java b/src/com/vaadin/demo/featurebrowser/JavaScriptAPIExample.java
new file mode 100644
index 0000000000..4656263163
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/JavaScriptAPIExample.java
@@ -0,0 +1,97 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import java.util.Date;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * An example using a RichTextArea to edit a Label in XHTML-mode.
+ *
+ */
+public class JavaScriptAPIExample extends CustomComponent {
+
+ public static final String txt = "<p>For advanced client side programmers Toolkit offers a simple method which can be used to force sync client with server. This may be needed for example if another part of a mashup changes things on server.</p> (more examples will be added here as the APIs are made public)<br/><br/><A href=\"javascript:itmill.forceSync();\">javascript:itmill.forceSync();</A>";
+
+ private final VerticalLayout main;
+ private final Label l;
+ private final TextField editor = new TextField();
+
+ public JavaScriptAPIExample() {
+ // main layout
+ main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+ editor.setRows(7);
+ editor.setColumns(50);
+ // Add the label
+ l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ main.addComponent(l);
+ // Edit button with inline click-listener
+ Button b = new Button("Edit", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // swap Label <-> RichTextArea
+ if (main.getComponentIterator().next() == l) {
+ editor.setValue(l.getValue());
+ main.replaceComponent(l, editor);
+ event.getButton().setCaption("Save");
+ } else {
+ l.setValue(editor.getValue());
+ main.replaceComponent(editor, l);
+ event.getButton().setCaption("Edit");
+ }
+ }
+ });
+ main.addComponent(b);
+ main.setComponentAlignment(b, Alignment.MIDDLE_RIGHT);
+
+ //
+ Label l = new Label(
+ "This label will update it's server-side value AFTER it's rendered to the client-side. "
+ + "The client will be synchronized on reload, when you click a button, "
+ + "or when itmill.forceSync() is called.") {
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+
+ super.paintContent(target);
+ Delay d = new Delay(this);
+ d.start();
+ }
+
+ };
+ main.addComponent(l);
+
+ }
+
+ private class Delay extends Thread {
+ Label label;
+
+ public Delay(Label l) {
+ label = l;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(500);
+ label.setValue(new Date().toString());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/LabelExample.java b/src/com/vaadin/demo/featurebrowser/LabelExample.java
new file mode 100644
index 0000000000..1d197455c8
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/LabelExample.java
@@ -0,0 +1,77 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+
+/**
+ * Shows a few variations of Labels, including the effects of XHTML- and
+ * pre-formatted mode.
+ *
+ * @author IT Mill Ltd.
+ */
+public class LabelExample extends CustomComponent {
+
+ private static final String xhtml = "This text has <b>HTML</b> formatting.<br/>"
+ + "A plain <i>Label</i> will show the markup, while a <u>XHTML-mode</u>"
+ + " <i>Label</i> will show the formatted text.";
+
+ private static final String pre = "This text has linebreaks.\n\n"
+ + "They will show up in a preformatted Label,\n"
+ + "but not in a \"plain\" Label.\n\n"
+ + " This is an indented row. \n Same indentation here.";
+
+ public LabelExample() {
+ final GridLayout g = new GridLayout(2, 4);
+ g.setMargin(true);
+ setCompositionRoot(g);
+ g.setWidth("100%");
+
+ // plain w/o caption
+ Panel p = getExpamplePanel("Plain");
+ Label l = new Label("A plain label without caption.");
+ p.addComponent(l);
+ g.addComponent(p);
+ // plain w/ caption
+ p = getExpamplePanel("Plain w/ caption + tooltip");
+ l = new Label("A plain label with caption.");
+ l.setCaption("Label caption");
+ l.setDescription("This is a description (tooltip) for the label.");
+ p.addComponent(l);
+ g.addComponent(p);
+ // plain w/ xhtml
+ p = getExpamplePanel("Plain w/ XHTML content");
+ l = new Label(xhtml);
+ p.addComponent(l);
+ g.addComponent(p);
+ // xhtml w/ xhtml
+ p = getExpamplePanel("XHTML-mode w/ XHTML content");
+ l = new Label(xhtml);
+ l.setContentMode(Label.CONTENT_XHTML);
+ p.addComponent(l);
+ g.addComponent(p);
+ // plain w/ preformatted
+ p = getExpamplePanel("Plain w/ preformatted content");
+ l = new Label(pre);
+ p.addComponent(l);
+ g.addComponent(p);
+ // preformatted w/ preformatted
+ p = getExpamplePanel("Preformatted-mode w/ preformatted content");
+ l = new Label(pre);
+ l.setContentMode(Label.CONTENT_PREFORMATTED);
+ p.addComponent(l);
+ g.addComponent(p);
+
+ }
+
+ private Panel getExpamplePanel(String caption) {
+ Panel p = new Panel(caption);
+ p.addStyleName(Panel.STYLE_LIGHT);
+ return p;
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/LayoutExample.java b/src/com/vaadin/demo/featurebrowser/LayoutExample.java
new file mode 100644
index 0000000000..d6f8e82070
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/LayoutExample.java
@@ -0,0 +1,88 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * A few examples of layout possibilities.
+ *
+ * @author IT Mill Ltd.
+ */
+public class LayoutExample extends CustomComponent {
+
+ public LayoutExample() {
+
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final GridLayout g = new GridLayout(2, 5);
+ g.setWidth("100%");
+ main.addComponent(g);
+
+ // panel
+ Panel p = new Panel("This is a normal panel");
+ Label l = new Label("A normal panel.");
+ p.addComponent(l);
+ g.addComponent(p);
+ // lightpanel
+ p = new Panel("This is a light panel");
+ p.setStyleName(Panel.STYLE_LIGHT);
+ l = new Label("A light-style panel.");
+ p.addComponent(l);
+ g.addComponent(p);
+
+ TabSheet ts = new TabSheet();
+ g.addComponent(ts, 0, 1, 1, 1);
+
+ VerticalLayout ol = new VerticalLayout();
+ ol.setMargin(true);
+ ol.addComponent(new Label("Component 1"));
+ ol.addComponent(new Label("Component 2"));
+ ol.addComponent(new Label("Component 3"));
+ ts.addTab(ol, "Vertical OrderedLayout", null);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setMargin(true);
+ hl.addComponent(new Label("Component 1"));
+ hl.addComponent(new Label("Component 2"));
+ hl.addComponent(new Label("Component 3"));
+ ts.addTab(hl, "Horizontal OrderedLayout", null);
+
+ final GridLayout gl = new GridLayout(3, 3);
+ gl.setMargin(true);
+ gl.addComponent(new Label("Component 1.1"));
+ gl.addComponent(new Label("Component 1.2"));
+ gl.addComponent(new Label("Component 1.3"));
+ gl.addComponent(new Label("Component 2.2"), 1, 1);
+ gl.addComponent(new Label("Component 3.1"), 0, 2);
+ gl.addComponent(new Label("Component 3.3"), 2, 2);
+ ts.addTab(gl, "GridLayout", null);
+
+ /*- TODO spitpanel removed for now - do we need it here?
+ ts = new TabSheet();
+ ts.setHeight(150);
+ g.addComponent(ts, 0, 2, 1, 2);
+
+ SplitPanel sp = new SplitPanel();
+ sp.addComponent(new Label("Component 1"));
+ sp.addComponent(new Label("Component 2"));
+ ts.addTab(sp, "Vertical SplitPanel", null);
+
+ sp = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL);
+ sp.addComponent(new Label("Component 1"));
+ sp.addComponent(new Label("Component 2"));
+ ts.addTab(sp, "Horizontal SplitPanel", null);
+ -*/
+
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/NotificationExample.java b/src/com/vaadin/demo/featurebrowser/NotificationExample.java
new file mode 100644
index 0000000000..4c796d7b48
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/NotificationExample.java
@@ -0,0 +1,95 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.data.Item;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+/**
+ * Demonstrates the use of Notifications.
+ *
+ * @author IT Mill Ltd.
+ * @see com.vaadin.ui.Window
+ */
+public class NotificationExample extends CustomComponent {
+
+ // Dropdown select for notification type, using the native dropdown
+ NativeSelect type;
+ // Textfield for the notification caption
+ TextField caption;
+ // Textfield for the notification content
+ TextField message;
+
+ /**
+ * Default constructor; We're subclassing CustomComponent, so we need to
+ * choose a root component and set it as composition root.
+ */
+ public NotificationExample() {
+ // Main layout
+ final VerticalLayout main = new VerticalLayout();
+ main.setSizeUndefined();
+ main.setSpacing(true);
+ main.setMargin(true); // use theme-specific margin
+ setCompositionRoot(main);
+
+ // Create the 'type' dropdown select.
+ type = new NativeSelect("Notification type");
+ main.addComponent(type);
+ // no empty selection allowed
+ type.setNullSelectionAllowed(false);
+ // we want a different caption than the value
+ type.addContainerProperty("caption", String.class, null);
+ type.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+ type.setItemCaptionPropertyId("caption");
+ // add some content (items) using the Container API
+ Item i = type.addItem(new Integer(
+ Window.Notification.TYPE_HUMANIZED_MESSAGE));
+ i.getItemProperty("caption").setValue("Humanized message");
+ i = type.addItem(new Integer(Window.Notification.TYPE_WARNING_MESSAGE));
+ i.getItemProperty("caption").setValue("Warning message");
+ i = type.addItem(new Integer(Window.Notification.TYPE_ERROR_MESSAGE));
+ i.getItemProperty("caption").setValue("Error message");
+ i = type
+ .addItem(new Integer(Window.Notification.TYPE_TRAY_NOTIFICATION));
+ i.getItemProperty("caption").setValue("Tray notification");
+ // set the initially selected item
+ type.setValue(new Integer(Window.Notification.TYPE_HUMANIZED_MESSAGE));
+
+ // Notification caption
+ caption = new TextField("Caption");
+ main.addComponent(caption);
+ caption.setColumns(20);
+ caption.setValue("Brown Fox!");
+
+ // Notification message
+ message = new RichTextArea();
+ main.addComponent(message);
+ message.setCaption("Message");
+ message.setValue("A quick one jumped over the lazy dog.");
+
+ // Button to show the notification
+ final Button b = new Button("Show notification", new ClickListener() {
+ // this is an inline ClickListener
+ public void buttonClick(ClickEvent event) {
+ // show the notification
+ getWindow().showNotification((String) caption.getValue(),
+ (String) message.getValue(),
+ ((Integer) type.getValue()).intValue());
+ }
+ });
+ main.addComponent(b);
+ main.setComponentAlignment(b, Alignment.MIDDLE_RIGHT);
+ }
+}
diff --git a/src/com/vaadin/demo/featurebrowser/RichTextExample.java b/src/com/vaadin/demo/featurebrowser/RichTextExample.java
new file mode 100644
index 0000000000..475f128e7a
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/RichTextExample.java
@@ -0,0 +1,63 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * An example using a RichTextArea to edit a Label in XHTML-mode.
+ *
+ */
+public class RichTextExample extends CustomComponent {
+
+ public static final String txt = "<h1>RichText editor example</h1>"
+ + "To edit this text, press the <b>Edit</b> button below."
+ + "<br/>"
+ + "See the <A href=\"http://www.itmill.com/documentation/itmill-toolkit-5-reference-manual/\">manual</a> "
+ + "for more information.";
+
+ private final VerticalLayout main;
+ private final Label l;
+ private final RichTextArea editor = new RichTextArea();
+ private final Button b;
+
+ public RichTextExample() {
+ // main layout
+ main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ editor.setWidth("100%");
+
+ // Add the label
+ l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ main.addComponent(l);
+ // Edit button with inline click-listener
+ b = new Button("Edit", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // swap Label <-> RichTextArea
+ if (main.getComponentIterator().next() == l) {
+ editor.setValue(l.getValue());
+ main.replaceComponent(l, editor);
+ b.setCaption("Save");
+ } else {
+ l.setValue(editor.getValue());
+ main.replaceComponent(editor, l);
+ b.setCaption("Edit");
+ }
+ }
+ });
+ main.addComponent(b);
+ main.setComponentAlignment(b, Alignment.MIDDLE_RIGHT);
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/SelectExample.java b/src/com/vaadin/demo/featurebrowser/SelectExample.java
new file mode 100644
index 0000000000..44a5343784
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/SelectExample.java
@@ -0,0 +1,102 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.ListSelect;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.OptionGroup;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TwinColSelect;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * Shows some basic fields for value input; TextField, DateField, Slider...
+ *
+ * @author IT Mill Ltd.
+ */
+public class SelectExample extends CustomComponent {
+
+ // listener that shows a value change notification
+ private final Field.ValueChangeListener listener = new Field.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("" + event.getProperty().getValue());
+ }
+ };
+
+ public SelectExample() {
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ final Panel single = new Panel("Single selects");
+ single.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(single);
+ final Panel multi = new Panel("Multi selects");
+ multi.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(multi);
+
+ // radio button group
+ AbstractSelect sel = new OptionGroup("OptionGroup");
+ initSelect(sel);
+ single.addComponent(sel);
+ // checkbox group
+ sel = new OptionGroup("OptionGroup");
+ sel.setMultiSelect(true); // TODO: throws if set after listener - why?
+ initSelect(sel);
+ multi.addComponent(sel);
+ // single-select list
+ sel = new ListSelect("ListSelect");
+ ((ListSelect) sel).setColumns(15);
+ initSelect(sel);
+ single.addComponent(sel);
+ // multi-select list
+ sel = new ListSelect("ListSelect");
+ ((ListSelect) sel).setColumns(15);
+ sel.setMultiSelect(true);
+ initSelect(sel);
+ multi.addComponent(sel);
+ // native-style dropdows
+ sel = new NativeSelect("NativeSelect");
+ ((NativeSelect) sel).setColumns(15);
+ initSelect(sel);
+ single.addComponent(sel);
+ // combobox
+ sel = new ComboBox("ComboBox");
+ ((ComboBox) sel).setWidth("15em");
+ initSelect(sel);
+ single.addComponent(sel);
+ // "twin column" select
+ sel = new TwinColSelect("TwinColSelect");
+ sel.setWidth("100%");
+ ((TwinColSelect) sel).setColumns(15);
+ initSelect(sel);
+ multi.addComponent(sel);
+ }
+
+ /*
+ * Initialize select with some values, make immediate and add listener.
+ */
+ private void initSelect(AbstractSelect sel) {
+ for (int i = 1; i <= 5; i++) {
+ sel.addItem("Item " + i);
+ }
+ // select one item
+ sel.select("Item 1");
+
+ // make immediate, add listener
+ sel.setImmediate(true);
+ sel.addListener(listener);
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/TableExample.java b/src/com/vaadin/demo/featurebrowser/TableExample.java
new file mode 100644
index 0000000000..f1dfc1f187
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/TableExample.java
@@ -0,0 +1,298 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.event.Action;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * Table example.
+ *
+ * @author IT Mill Ltd.
+ */
+public class TableExample extends CustomComponent implements Action.Handler,
+ Button.ClickListener {
+
+ // Actions
+ private static final Action ACTION_SAVE = new Action("Save");
+ private static final Action ACTION_DELETE = new Action("Delete");
+ private static final Action ACTION_HIRE = new Action("Hire");
+ // Action sets
+ private static final Action[] ACTIONS_NOHIRE = new Action[] { ACTION_SAVE,
+ ACTION_DELETE };
+ private static final Action[] ACTIONS_HIRE = new Action[] { ACTION_HIRE,
+ ACTION_SAVE, ACTION_DELETE };
+ // Properties
+ private static final Object PROPERTY_SPECIES = "Species";
+ private static final Object PROPERTY_TYPE = "Type";
+ private static final Object PROPERTY_KIND = "Kind";
+ private static final Object PROPERTY_HIRED = "Hired";
+
+ // "global" components
+ Table source;
+ Table saved;
+ Button saveSelected;
+ Button hireSelected;
+ Button deleteSelected;
+ Button deselect;
+
+ public TableExample() {
+ VerticalLayout margin = new VerticalLayout();
+ margin.setMargin(true);
+
+ TabSheet root = new TabSheet();
+ setCompositionRoot(margin);
+ margin.addComponent(root);
+
+ // main layout
+ final VerticalLayout main = new VerticalLayout();
+ root.addComponent(main);
+ main.setCaption("Basic Table");
+ main.setMargin(true);
+
+ // "source" table with bells & whistlesenabled
+ source = new Table("All creatures");
+ source.setPageLength(7);
+ source.setWidth("550px");
+ source.setColumnCollapsingAllowed(true);
+ source.setColumnReorderingAllowed(true);
+ source.setSelectable(true);
+ source.setMultiSelect(true);
+ source.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ fillTable(source);
+ source.addActionHandler(this);
+ main.addComponent(source);
+
+ // x-selected button row
+ final HorizontalLayout horiz = new HorizontalLayout();
+
+ horiz.setMargin(false, false, true, false);
+ main.addComponent(horiz);
+ saveSelected = new Button("Save selected");
+ saveSelected.setStyleName(Button.STYLE_LINK);
+ saveSelected.addListener(this);
+ horiz.addComponent(saveSelected);
+ hireSelected = new Button("Hire selected");
+ hireSelected.setStyleName(Button.STYLE_LINK);
+ hireSelected.addListener(this);
+ horiz.addComponent(hireSelected);
+ deleteSelected = new Button("Delete selected");
+ deleteSelected.setStyleName(Button.STYLE_LINK);
+ deleteSelected.addListener(this);
+ horiz.addComponent(deleteSelected);
+ deselect = new Button("Deselect all");
+ deselect.setStyleName(Button.STYLE_LINK);
+ deselect.addListener(this);
+ horiz.addComponent(deselect);
+ final CheckBox editmode = new CheckBox("Editmode ");
+ editmode.addListener(new CheckBox.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ source.setEditable(((Boolean) event.getButton().getValue())
+ .booleanValue());
+ }
+ });
+ editmode.setImmediate(true);
+ horiz.addComponent(editmode);
+
+ // "saved" table, minimalistic
+ saved = new Table("Saved creatures");
+ saved.setPageLength(5);
+ saved.setWidth("550px");
+ saved.setSelectable(false);
+ saved.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN);
+ saved.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ initProperties(saved);
+ saved.addActionHandler(this);
+ main.addComponent(saved);
+
+ final CheckBox b = new CheckBox("Modify saved creatures");
+ b.addListener(new CheckBox.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ saved.setEditable(((Boolean) event.getButton().getValue())
+ .booleanValue());
+ }
+ });
+ b.setImmediate(true);
+ main.addComponent(b);
+
+ GeneratedColumnExample gencols = new GeneratedColumnExample();
+ gencols.setCaption("Generated Columns");
+ root.addComponent(gencols);
+ }
+
+ // set up the properties (columns)
+ private void initProperties(Table table) {
+ table.addContainerProperty(PROPERTY_SPECIES, String.class, "");
+ table.addContainerProperty(PROPERTY_TYPE, String.class, "");
+ table.addContainerProperty(PROPERTY_KIND, String.class, "");
+ table
+ .addContainerProperty(PROPERTY_HIRED, Boolean.class,
+ Boolean.FALSE);
+ }
+
+ // fill the table with some random data
+ private void fillTable(Table table) {
+ initProperties(table);
+
+ final String[] sp = new String[] { "Fox", "Dog", "Cat", "Moose",
+ "Penguin", "Cow" };
+ final String[] ty = new String[] { "Quick", "Lazy", "Sleepy",
+ "Fidgety", "Crazy", "Kewl" };
+ final String[] ki = new String[] { "Jumping", "Walking", "Sleeping",
+ "Skipping", "Dancing" };
+
+ Random r = new Random(5);
+
+ for (int i = 0; i < 100; i++) {
+ final String s = sp[(int) (r.nextDouble() * sp.length)];
+ final String t = ty[(int) (r.nextDouble() * ty.length)];
+ final String k = ki[(int) (r.nextDouble() * ki.length)];
+ table.addItem(new Object[] { s, t, k, Boolean.FALSE }, new Integer(
+ i));
+ }
+
+ }
+
+ // Called for each item (row), returns valid actions for that item
+ public Action[] getActions(Object target, Object sender) {
+ if (sender == source) {
+ final Item item = source.getItem(target);
+ // save, delete, and hire if not already hired
+ if (item != null
+ && item.getItemProperty(PROPERTY_HIRED).getValue() == Boolean.FALSE) {
+ return ACTIONS_HIRE;
+ } else {
+ return ACTIONS_NOHIRE;
+ }
+ } else {
+ // "saved" table only has one action
+ return new Action[] { ACTION_DELETE };
+ }
+ }
+
+ // called when an action is invoked on an item (row)
+ public void handleAction(Action action, Object sender, Object target) {
+ if (sender == source) {
+ Item item = source.getItem(target);
+ if (action == ACTION_HIRE) {
+ // set HIRED property to true
+ item.getItemProperty(PROPERTY_HIRED).setValue(Boolean.TRUE);
+ if (saved.containsId(target)) {
+ item = saved.getItem(target);
+ item.getItemProperty(PROPERTY_HIRED).setValue(Boolean.TRUE);
+ }
+ getWindow().showNotification("Hired", "" + item);
+
+ } else if (action == ACTION_SAVE) {
+ if (saved.containsId(target)) {
+ // let's not save twice
+ getWindow().showNotification("Already saved", "" + item);
+ return;
+ }
+ // "manual" copy of the item properties we want
+ final Item added = saved.addItem(target);
+ Property p = added.getItemProperty(PROPERTY_SPECIES);
+ p.setValue(item.getItemProperty(PROPERTY_SPECIES).getValue());
+ p = added.getItemProperty(PROPERTY_TYPE);
+ p.setValue(item.getItemProperty(PROPERTY_TYPE).getValue());
+ p = added.getItemProperty(PROPERTY_KIND);
+ p.setValue(item.getItemProperty(PROPERTY_KIND).getValue());
+ p = added.getItemProperty(PROPERTY_HIRED);
+ p.setValue(item.getItemProperty(PROPERTY_HIRED).getValue());
+ getWindow().showNotification("Saved", "" + item);
+ } else {
+ // ACTION_DELETE
+ getWindow().showNotification("Deleted ", "" + item);
+ source.removeItem(target);
+ }
+
+ } else {
+ // sender==saved
+ if (action == ACTION_DELETE) {
+ final Item item = saved.getItem(target);
+ getWindow().showNotification("Deleted", "" + item);
+ saved.removeItem(target);
+ }
+ }
+ }
+
+ public void buttonClick(ClickEvent event) {
+ final Button b = event.getButton();
+ if (b == deselect) {
+ source.setValue(null);
+ } else if (b == saveSelected) {
+ // loop each selected and copy to "saved" table
+ final Set selected = (Set) source.getValue();
+ int s = 0;
+ for (final Iterator it = selected.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ if (!saved.containsId(id)) {
+ final Item item = source.getItem(id);
+ final Item added = saved.addItem(id);
+ // "manual" copy of the properties we want
+ Property p = added.getItemProperty(PROPERTY_SPECIES);
+ p.setValue(item.getItemProperty(PROPERTY_SPECIES)
+ .getValue());
+ p = added.getItemProperty(PROPERTY_TYPE);
+ p.setValue(item.getItemProperty(PROPERTY_TYPE).getValue());
+ p = added.getItemProperty(PROPERTY_KIND);
+ p.setValue(item.getItemProperty(PROPERTY_KIND).getValue());
+ p = added.getItemProperty(PROPERTY_HIRED);
+ p.setValue(item.getItemProperty(PROPERTY_HIRED).getValue());
+ s++;
+ }
+ }
+ getWindow().showNotification("Saved " + s);
+
+ } else if (b == hireSelected) {
+ // loop each selected and set property HIRED to true
+ int s = 0;
+ final Set selected = (Set) source.getValue();
+ for (final Iterator it = selected.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ Item item = source.getItem(id);
+ final Property p = item.getItemProperty(PROPERTY_HIRED);
+ if (p.getValue() == Boolean.FALSE) {
+ p.setValue(Boolean.TRUE);
+ s++;
+ }
+ if (saved.containsId(id)) {
+ // also update "saved" table
+ item = saved.getItem(id);
+ item.getItemProperty(PROPERTY_HIRED).setValue(Boolean.TRUE);
+ }
+ }
+ getWindow().showNotification("Hired " + s);
+
+ } else {
+ // loop trough selected and delete
+ int s = 0;
+ final Set selected = (Set) source.getValue();
+ for (final Iterator it = selected.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ if (source.containsId(id)) {
+ s++;
+ source.removeItem(id);
+ }
+ }
+ getWindow().showNotification("Deleted " + s);
+ }
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/TreeExample.java b/src/com/vaadin/demo/featurebrowser/TreeExample.java
new file mode 100644
index 0000000000..c4d7a54a38
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/TreeExample.java
@@ -0,0 +1,162 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.event.Action;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Tree;
+
+/**
+ * Demonstrates basic Tree -functionality. Actions are used for add/remove item
+ * functionality, and a ValueChangeListener reacts to both the Tree and the
+ * TextField.
+ */
+public class TreeExample extends CustomComponent implements Action.Handler,
+ Tree.ValueChangeListener {
+
+ private static final Action ADD = new Action("Add item");
+ private static final Action DELETE = new Action("Delete item");
+ private static final Action[] actions = new Action[] { ADD, DELETE };
+
+ // Id for the caption property
+ private static final Object CAPTION_PROPERTY = "caption";
+
+ private static final String desc = "Try both right- and left-click!";
+
+ Tree tree;
+ TextField editor;
+
+ public TreeExample() {
+ final HorizontalLayout main = new HorizontalLayout();
+ main.setWidth("100%");
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ // Panel w/ Tree
+ Panel p = new Panel("Select item");
+ p.setStyleName(Panel.STYLE_LIGHT);
+ p.setWidth("250px");
+ // Description
+ p.addComponent(new Label(desc));
+ // Tree with a few items
+ tree = new Tree();
+ tree.setImmediate(true);
+ // we'll use a property for caption instead of the item id ("value"),
+ // so that multiple items can have the same caption
+ tree.addContainerProperty(CAPTION_PROPERTY, String.class, "");
+ tree.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+ tree.setItemCaptionPropertyId(CAPTION_PROPERTY);
+ for (int i = 1; i <= 3; i++) {
+ final Object id = addCaptionedItem("Section " + i, null);
+ tree.expandItem(id);
+ addCaptionedItem("Team A", id);
+ addCaptionedItem("Team B", id);
+ }
+ // listen for selections
+ tree.addListener(this);
+ // "context menu"
+ tree.addActionHandler(this);
+ p.addComponent(tree);
+ main.addComponent(p);
+
+ // Panel w/ TextField ("editor")
+ p = new Panel("Edit item caption");
+ p.setStyleName(Panel.STYLE_LIGHT);
+ editor = new TextField();
+ // make immediate, instead of adding an "apply" button
+ editor.setImmediate(true);
+ editor.setEnabled(false);
+ editor.setColumns(15);
+ p.addComponent(editor);
+ main.addComponent(p);
+ main.setExpandRatio(p, 1);
+ }
+
+ public Action[] getActions(Object target, Object sender) {
+ // We can provide different actions for each target (item), but we'll
+ // use the same actions all the time.
+ return actions;
+ }
+
+ public void handleAction(Action action, Object sender, Object target) {
+ if (action == DELETE) {
+ tree.removeItem(target);
+ } else {
+ // Add
+ final Object id = addCaptionedItem("New Item", target);
+ tree.expandItem(target);
+ tree.setValue(id);
+ editor.focus();
+ }
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ final Object id = tree.getValue(); // selected item id
+ if (event.getProperty() == tree) {
+ // a Tree item was (un) selected
+ if (id == null) {
+ // no selecteion, disable TextField
+ editor.removeListener(this);
+ editor.setValue("");
+ editor.setEnabled(false);
+ } else {
+ // item selected
+ // first remove previous listener
+ editor.removeListener(this);
+ // enable TextField and update value
+ editor.setEnabled(true);
+ final Item item = tree.getItem(id);
+ editor.setValue(item.getItemProperty(CAPTION_PROPERTY)
+ .getValue());
+ // listen for TextField changes
+ editor.addListener(this);
+ editor.focus();
+ }
+ } else {
+ // TextField
+ if (id != null) {
+ final Item item = tree.getItem(id);
+ final Property p = item.getItemProperty(CAPTION_PROPERTY);
+ p.setValue(editor.getValue());
+ tree.requestRepaint();
+ }
+
+ }
+ }
+
+ /**
+ * Helper to add an item with specified caption and (optional) parent.
+ *
+ * @param caption
+ * The item caption
+ * @param parent
+ * The (optional) parent item id
+ * @return the created item's id
+ */
+ private Object addCaptionedItem(String caption, Object parent) {
+ // add item, let tree decide id
+ final Object id = tree.addItem();
+ // get the created item
+ final Item item = tree.getItem(id);
+ // set our "caption" property
+ final Property p = item.getItemProperty(CAPTION_PROPERTY);
+ p.setValue(caption);
+ if (parent != null) {
+ tree.setChildrenAllowed(parent, true);
+ tree.setParent(id, parent);
+ tree.setChildrenAllowed(id, false);
+ }
+ return id;
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/ValueInputExample.java b/src/com/vaadin/demo/featurebrowser/ValueInputExample.java
new file mode 100644
index 0000000000..455acc3625
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/ValueInputExample.java
@@ -0,0 +1,146 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.Slider;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window.Notification;
+
+/**
+ * Shows some basic fields for value input; TextField, DateField, Slider...
+ *
+ * @author IT Mill Ltd.
+ */
+public class ValueInputExample extends CustomComponent {
+
+ public ValueInputExample() {
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ // listener that shows a value change notification
+ final Field.ValueChangeListener listener = new Field.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Received",
+ "<pre>" + event.getProperty().getValue() + "</pre>",
+ Notification.TYPE_WARNING_MESSAGE);
+ }
+ };
+
+ // TextField
+ HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ Panel left = new Panel("TextField");
+ left.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(left);
+ Panel right = new Panel("multiline");
+ right.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(right);
+ // basic TextField
+ TextField tf = new TextField("Basic");
+ tf.setColumns(15);
+ tf.setImmediate(true);
+ tf.addListener(listener);
+ left.addComponent(tf);
+ // multiline TextField a.k.a TextArea
+ tf = new TextField("Area");
+ tf.setColumns(15);
+ tf.setRows(5);
+ tf.setImmediate(true);
+ tf.addListener(listener);
+ right.addComponent(tf);
+
+ // DateFields
+ horiz = new HorizontalLayout();
+ horiz.setWidth("100%");
+ main.addComponent(horiz);
+ left = new Panel("DateField");
+ left.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(left);
+ right = new Panel("inline");
+ right.setStyleName(Panel.STYLE_LIGHT);
+ horiz.addComponent(right);
+ // default
+ DateField df = new DateField("Day resolution");
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_DAY);
+ left.addComponent(df);
+ // minute
+ df = new DateField("Minute resolution");
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_MIN);
+ left.addComponent(df);
+ // year
+ df = new DateField("Year resolution");
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_YEAR);
+ left.addComponent(df);
+ // msec
+ df = new DateField("Millisecond resolution");
+ df.addListener(listener);
+ df.setImmediate(true);
+ df.setResolution(DateField.RESOLUTION_MSEC);
+ left.addComponent(df);
+ // Inline
+ df = new InlineDateField();
+ df.addListener(listener);
+ df.setImmediate(true);
+ right.addComponent(df);
+
+ // Slider
+ left = new Panel("Slider");
+ left.setStyleName(Panel.STYLE_LIGHT);
+ main.addComponent(left);
+ // int slider
+ Slider slider = new Slider(0, 100);
+ slider.setWidth("300px");
+ // slider.setSize(300);
+ slider.setImmediate(true);
+ slider.addListener(new Slider.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // update caption when value changes
+ final Slider s = (Slider) event.getProperty();
+ s.setCaption("Value: " + s.getValue());
+ }
+ });
+ try {
+ slider.setValue(20);
+ } catch (final Exception e) {
+ e.printStackTrace(System.err);
+ }
+ left.addComponent(slider);
+ // double slider
+ slider = new Slider(0.0, 1.0, 1);
+ slider.setOrientation(Slider.ORIENTATION_VERTICAL);
+ slider.setImmediate(true);
+ slider.addListener(new Slider.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // update caption when value changes
+ final Slider s = (Slider) event.getProperty();
+ s.setCaption("Value: " + s.getValue());
+ }
+ });
+ try {
+ slider.setValue(0.5);
+ } catch (final Exception e) {
+ e.printStackTrace(System.err);
+ }
+ left.addComponent(slider);
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/featurebrowser/WindowingExample.java b/src/com/vaadin/demo/featurebrowser/WindowingExample.java
new file mode 100644
index 0000000000..23c579d19b
--- /dev/null
+++ b/src/com/vaadin/demo/featurebrowser/WindowingExample.java
@@ -0,0 +1,112 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.featurebrowser;
+
+import java.net.URL;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+/**
+ * @author marc
+ *
+ */
+public class WindowingExample extends CustomComponent {
+
+ public static final String txt = "<p>There are two main types of windows: application-level windows, and "
+ + "\"sub windows\".</p><p>A sub window is rendered as a \"inline\" popup window"
+ + " within the (native) browser window to which it was added. You can create"
+ + " a sub window by creating a new Window and adding it to a application-level window, for instance"
+ + " your main window. </p><p> In contrast, you create a application-level window by"
+ + " creating a new Window and adding it to the Application. Application-level"
+ + " windows are not shown by default - you need to open a browser window for"
+ + " the url representing the window. You can think of the application-level"
+ + " windows as separate views into your application - and a way to create a"
+ + " \"native\" browser window.</p><p>Depending on your needs, it's also"
+ + " possible to create a new window instance (with it's own internal state)"
+ + " for each new (native) browser window, or you can share the same instance"
+ + " (and state) between several browser windows (the latter is most useful"
+ + " for read-only views).</p>";
+
+ private URL windowUrl = null;
+
+ public WindowingExample() {
+ final VerticalLayout main = new VerticalLayout();
+ main.setMargin(true);
+ setCompositionRoot(main);
+
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ main.addComponent(l);
+
+ Button b = new Button("Create a new subwindow",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ final Window w = new Window("Subwindow");
+ w.setWidth("50%");
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ w.addComponent(l);
+ getApplication().getMainWindow().addWindow(w);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+ b = new Button("Create a new modal window", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ final Window w = new Window("Modal window");
+ w.setWidth("50%");
+ w.setModal(true);
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ w.addComponent(l);
+ getApplication().getMainWindow().addWindow(w);
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+ b = new Button("Open a application-level window, with shared state",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (windowUrl == null) {
+ final Window w = new Window("Subwindow");
+ final Label l = new Label(txt);
+ l.setContentMode(Label.CONTENT_XHTML);
+ w.addComponent(l);
+ getApplication().addWindow(w);
+ windowUrl = w.getURL();
+ }
+ getApplication().getMainWindow().open(
+ new ExternalResource(windowUrl), "_new");
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+ b = new Button(
+ "Create a new application-level window, with it's own state",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ final Window w = new Window("Subwindow");
+ getApplication().addWindow(w);
+ final Label l = new Label(
+ "Each opened window has its own"
+ + " name, and is accessed trough its own uri.");
+ l.setCaption("Window " + w.getName());
+ w.addComponent(l);
+ getApplication().getMainWindow().open(
+ new ExternalResource(w.getURL()), "_new");
+ }
+ });
+ b.setStyleName(Button.STYLE_LINK);
+ main.addComponent(b);
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/package.html b/src/com/vaadin/demo/package.html
new file mode 100644
index 0000000000..d9bb6824f7
--- /dev/null
+++ b/src/com/vaadin/demo/package.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+</head>
+
+<body bgcolor="white">
+
+<p>Provides several fully functional IT Mill Toolkit example applications. These
+highlight certain aspects of the toolkit and how it can be
+used to produce simple, elegant yet powerful user interface driven
+applications.</p>
+
+<ul>
+<li><strong>HelloWorld</strong> is the classic example which only prints the
+text "Hello, World!" on the screen.</li>
+<li><strong>Calc</strong> implements a calculator application which
+demonstrates how to build a bit more complicated user interface and how the
+application can interact with the usern through that interface.</li>
+</ul>
+
+</body>
+</html>
diff --git a/src/com/vaadin/demo/reservation/CalendarDemo.java b/src/com/vaadin/demo/reservation/CalendarDemo.java
new file mode 100644
index 0000000000..5c4571fda6
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/CalendarDemo.java
@@ -0,0 +1,120 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation;
+
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.Date;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.util.QueryContainer;
+import com.vaadin.demo.util.SampleCalendarDatabase;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.Window;
+
+/**
+ * This example shows how the CalendarField can use Containers. A QueryContainer
+ * is used to bind SQL table rows to the calendar. Demonstrates: how to create
+ * <code>com.vaadin.data.Container</code> and set it as datasource for
+ * <code>com.vaadin.ui.Component.CalendarField</code>
+ *
+ * @author IT Mill Ltd.
+ * @since 4.0.0
+ *
+ */
+public class CalendarDemo extends com.vaadin.Application {
+
+ // Database provided with sample data
+ private SampleCalendarDatabase sampleDatabase;
+
+ // The calendar UI component
+ private CalendarField from;
+ private CalendarField to;
+
+ /**
+ * Initialize Application. Demo components are added to main window.
+ */
+ @Override
+ public void init() {
+ final Window main = new Window("Calendar demo");
+ setMainWindow(main);
+
+ main.setLayout(new OrderedLayout(OrderedLayout.ORIENTATION_HORIZONTAL));
+
+ // create the calendar component and add to layout
+ from = new CalendarField();
+ main.addComponent(from);
+ from.setResolution(DateField.RESOLUTION_HOUR);
+ from.setImmediate(true);
+
+ to = new CalendarField();
+ main.addComponent(to);
+ to.setResolution(DateField.RESOLUTION_HOUR);
+ to.setEnabled(false);
+ to.setImmediate(true);
+
+ from.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ final Date fd = (Date) from.getValue();
+ final Date td = (Date) to.getValue();
+ if (fd == null) {
+ to.setValue(null);
+ to.setEnabled(false);
+ return;
+ } else {
+ to.setEnabled(true);
+ }
+ to.setMinimumDate(fd);
+ if (td == null || td.before(fd)) {
+ to.setValue(fd);
+ }
+ }
+ });
+
+ // initialize the sample database and set as calendar datasource
+ sampleDatabase = new SampleCalendarDatabase();
+
+ initCalendars();
+
+ // Don't allow dates before today
+ from.setMinimumDate(Calendar.getInstance().getTime());
+
+ }
+
+ /**
+ * Populates table component with all rows from calendar table.
+ */
+ private void initCalendars() {
+ try {
+ final QueryContainer qc = new QueryContainer("SELECT * FROM "
+ + SampleCalendarDatabase.DB_TABLE_NAME, sampleDatabase
+ .getConnection());
+ from.setContainerDataSource(qc);
+ to.setContainerDataSource(qc);
+ } catch (final SQLException e) {
+ e.printStackTrace();
+ }
+ /*
+ * // Calendar will use the first date property as start if you do not
+ * // explicitly specify the property id. Our start -property will be
+ * the // first one, so it's intentionally left out. // Start is the
+ * only mandatory property, but you'll probably want to // specify title
+ * as well.
+ * from.setItemEndPropertyId(SampleCalendarDatabase.PROPERTY_ID_END);
+ * from
+ * .setItemTitlePropertyId(SampleCalendarDatabase.PROPERTY_ID_TITLE);
+ * from
+ * .setItemNotimePropertyId(SampleCalendarDatabase.PROPERTY_ID_NOTIME);
+ *
+ * to.setItemEndPropertyId(SampleCalendarDatabase.PROPERTY_ID_END);
+ * to.setItemTitlePropertyId(SampleCalendarDatabase.PROPERTY_ID_TITLE);
+ * to
+ * .setItemNotimePropertyId(SampleCalendarDatabase.PROPERTY_ID_NOTIME);
+ */
+ }
+
+}
diff --git a/src/com/vaadin/demo/reservation/CalendarField.java b/src/com/vaadin/demo/reservation/CalendarField.java
new file mode 100644
index 0000000000..429f04ecbe
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/CalendarField.java
@@ -0,0 +1,331 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation;
+
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.DateField;
+
+// TODO send one month at a time, do lazyLoading
+// TODO check date limit when updating variables
+// TODO Allow item selection
+public class CalendarField extends DateField implements Container.Viewer {
+
+ private static final String TAGNAME = "calendarfield";
+
+ private Date minDate;
+ private Date maxDate;
+
+ private Container dataSource;
+ private Object itemStyleNamePropertyId;
+ private Object itemStartPropertyId;
+ private Object itemEndPropertyId;
+ private Object itemTitlePropertyId;
+ private Object itemDescriptionPropertyId;
+ private Object itemNotimePropertyId;
+
+ public CalendarField() {
+ super();
+ init();
+ }
+
+ public CalendarField(Property dataSource) throws IllegalArgumentException {
+ super(dataSource);
+ init();
+ }
+
+ public CalendarField(String caption, Date value) {
+ super(caption, value);
+ init();
+ }
+
+ public CalendarField(String caption, Property dataSource) {
+ super(caption, dataSource);
+ init();
+ }
+
+ public CalendarField(String caption) {
+ super(caption);
+ init();
+ }
+
+ /*
+ * Gets the components UIDL tag string. Don't add a JavaDoc comment here, we
+ * use the default documentation from implemented interface.
+ */
+ @Override
+ public String getTag() {
+ return TAGNAME;
+ }
+
+ public void init() {
+ super.setResolution(RESOLUTION_HOUR);
+
+ }
+
+ /**
+ * Sets the resolution of the CalendarField. Only RESOLUTION_DAY and
+ * RESOLUTION_HOUR are supported.
+ *
+ * @param resolution
+ * the resolution to set.
+ * @see com.vaadin.ui.DateField#setResolution(int)
+ */
+ @Override
+ public void setResolution(int resolution) {
+ if (resolution != RESOLUTION_DAY && resolution != RESOLUTION_HOUR) {
+ throw new IllegalArgumentException();
+ }
+ super.setResolution(resolution);
+ }
+
+ public void setMinimumDate(Date date) {
+ minDate = date;
+ requestRepaint();
+ }
+
+ public Date getMinimumDate() {
+ return minDate;
+ }
+
+ public void setMaximumDate(Date date) {
+ maxDate = date;
+ requestRepaint();
+ }
+
+ public Date getMaximumDate() {
+ return maxDate;
+ }
+
+ public Container getContainerDataSource() {
+ return dataSource;
+ }
+
+ public void setContainerDataSource(Container newDataSource) {
+ if (newDataSource == null || checkDataSource(newDataSource)) {
+ dataSource = newDataSource;
+ } else {
+ // TODO error message
+ throw new IllegalArgumentException();
+ }
+ requestRepaint();
+ }
+
+ private boolean checkDataSource(Container dataSource) {
+
+ // Check old propertyIds
+ if (itemEndPropertyId != null) {
+ final Class c = dataSource.getType(itemEndPropertyId);
+ if (!Date.class.isAssignableFrom(c)) {
+ itemEndPropertyId = null;
+ }
+ }
+ if (itemNotimePropertyId != null) {
+ final Class c = dataSource.getType(itemNotimePropertyId);
+ if (!Boolean.class.isAssignableFrom(c)) {
+ itemNotimePropertyId = null;
+ }
+ }
+ if (itemStartPropertyId != null) {
+ final Class c = dataSource.getType(itemStartPropertyId);
+ if (Date.class.isAssignableFrom(c)) {
+ // All we _really_ need is one date
+ return true;
+ } else {
+ itemStartPropertyId = null;
+ }
+ }
+ // We need at least one Date
+ final Collection ids = dataSource.getContainerPropertyIds();
+ for (final Iterator it = ids.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ final Class c = dataSource.getType(id);
+ if (Date.class.isAssignableFrom(c)) {
+ itemStartPropertyId = id;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public Object getItemStyleNamePropertyId() {
+ return itemStyleNamePropertyId;
+ }
+
+ public void setItemStyleNamePropertyId(Object propertyId) {
+ itemStyleNamePropertyId = propertyId;
+ }
+
+ public Object getItemStartPropertyId() {
+ return itemStartPropertyId;
+ }
+
+ public void setItemStartPropertyId(Object propertyId) {
+ // TODO nullcheck for property id
+ if (dataSource != null
+ && !Date.class.isAssignableFrom(dataSource.getType(propertyId))) {
+ // TODO error message
+ throw new IllegalArgumentException();
+ }
+ itemStartPropertyId = propertyId;
+ }
+
+ public Object getItemEndPropertyId() {
+ return itemEndPropertyId;
+ }
+
+ public void setItemEndPropertyId(Object propertyId) {
+ // TODO nullcheck for property id
+ if (dataSource != null
+ && !Date.class.isAssignableFrom(dataSource.getType(propertyId))) {
+ // TODO error message
+ throw new IllegalArgumentException();
+ }
+ itemEndPropertyId = propertyId;
+ }
+
+ public Object getItemTitlePropertyId() {
+ return itemTitlePropertyId;
+ }
+
+ public void setItemTitlePropertyId(Object propertyId) {
+ itemTitlePropertyId = propertyId;
+ }
+
+ public Object getItemDescriptionPropertyId() {
+ return itemDescriptionPropertyId;
+ }
+
+ public void setItemDescriptionPropertyId(Object propertyId) {
+ itemDescriptionPropertyId = propertyId;
+ }
+
+ public Object getitemNotimePropertyId() {
+ return itemNotimePropertyId;
+ }
+
+ public void setItemNotimePropertyId(Object propertyId) {
+ // TODO nullcheck for property id
+ if (dataSource != null
+ && !Boolean.class.isAssignableFrom(dataSource
+ .getType(propertyId))) {
+ // TODO error message
+ throw new IllegalArgumentException();
+ }
+ itemNotimePropertyId = propertyId;
+ }
+
+ /**
+ * Paints the content of this component.
+ *
+ * @param target
+ * the Paint Event.
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+
+ if (minDate != null) {
+ target.addAttribute("min", String.valueOf(minDate.getTime()));
+ }
+ if (maxDate != null) {
+ target.addAttribute("max", String.valueOf(maxDate.getTime()));
+ }
+
+ if (dataSource != null) {
+ target.startTag("items");
+
+ // TODO send one month now, the rest via lazyloading
+ int month = new Date().getMonth();
+ final Object value = getValue();
+ if (value != null && value instanceof Date) {
+ month = ((Date) value).getMonth();
+ }
+
+ for (final Iterator it = dataSource.getItemIds().iterator(); it
+ .hasNext();) {
+ final Object itemId = it.next();
+ final Item item = dataSource.getItem(itemId);
+ Property p = item.getItemProperty(itemStartPropertyId);
+ Date start = (Date) p.getValue();
+ Date end = start; // assume same day
+ if (itemEndPropertyId != null) {
+ p = item.getItemProperty(itemEndPropertyId);
+ end = (Date) p.getValue();
+ if (end == null) {
+ end = start;
+ } else if (end.before(start)) {
+ final Date tmp = start;
+ start = end;
+ end = tmp;
+ }
+ }
+
+ // TODO half-done lazyloading logic (hence broken)
+
+ if (start != null) {
+ if ((start.getMonth() <= month || end.getMonth() >= month)) {
+ target.startTag("item");
+ // TODO different id?
+ target.addAttribute("id", itemId.hashCode());
+ if (itemStyleNamePropertyId != null) {
+ p = item.getItemProperty(itemStyleNamePropertyId);
+ final String styleName = (String) p.getValue();
+ target.addAttribute("styleName", styleName);
+ }
+ SimpleDateFormat sdf = new SimpleDateFormat(
+ "d MM yyyy HH:mm:ss Z");
+
+ target.addAttribute("Z", start.getTimezoneOffset());
+
+ target.addAttribute("start", "" + sdf.format(start));
+
+ if (end != start) {
+ target.addAttribute("end", "" + sdf.format(end));
+ }
+ if (itemTitlePropertyId != null) {
+ p = item.getItemProperty(itemTitlePropertyId);
+ final Object val = p.getValue();
+ if (val != null) {
+ target.addAttribute("title", val.toString());
+ }
+ }
+ if (itemDescriptionPropertyId != null) {
+ p = item.getItemProperty(itemDescriptionPropertyId);
+ final Object val = p.getValue();
+ if (val != null) {
+ target.addAttribute("description", val
+ .toString());
+ }
+ }
+ if (itemNotimePropertyId != null) {
+ p = item.getItemProperty(itemNotimePropertyId);
+ final Object val = p.getValue();
+ if (val != null) {
+ target.addAttribute("notime", ((Boolean) val)
+ .booleanValue());
+ }
+ }
+
+ target.endTag("item");
+ }
+ }
+ }
+
+ target.endTag("items");
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/reservation/GoogleMap.java b/src/com/vaadin/demo/reservation/GoogleMap.java
new file mode 100644
index 0000000000..9854227bc1
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/GoogleMap.java
@@ -0,0 +1,195 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation;
+
+import java.awt.geom.Point2D;
+import java.util.Collection;
+import java.util.Iterator;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Sizeable;
+import com.vaadin.ui.AbstractComponent;
+
+public class GoogleMap extends AbstractComponent implements Sizeable,
+ Container.Viewer {
+ private final String TAG_MARKERS = "markers";
+ private final String TAG_MARKER = "marker";
+ private int zoomLevel = 15;
+ private Point2D.Double mapCenter;
+
+ private Container dataSource;
+ private Object itemMarkerHtmlPropertyId = new Object();
+ private Object itemMarkerXPropertyId = new Object();
+ private Object itemMarkerYPropertyId = new Object();
+
+ @Override
+ public String getTag() {
+ return "googlemap";
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+ // Add size info as variables
+ if (getHeight() > -1) {
+ target.addVariable(this, "height", getHeight()
+ + UNIT_SYMBOLS[getHeightUnits()]);
+ }
+ if (getWidth() > -1) {
+ target.addVariable(this, "width", getWidth()
+ + UNIT_SYMBOLS[getWidthUnits()]);
+ }
+ if (null != mapCenter) {
+ target.addAttribute("centerX", mapCenter.getX());
+ target.addAttribute("centerY", mapCenter.getY());
+ }
+ target.addAttribute("zoom", zoomLevel);
+
+ if (dataSource != null) {
+ target.startTag(TAG_MARKERS);
+ final Collection itemIds = dataSource.getItemIds();
+ for (final Iterator it = itemIds.iterator(); it.hasNext();) {
+ final Object itemId = it.next();
+ final Item item = dataSource.getItem(itemId);
+ Property p = item.getItemProperty(getItemMarkerXPropertyId());
+ final Double x = (Double) (p != null ? p.getValue() : null);
+ p = item.getItemProperty(getItemMarkerYPropertyId());
+ final Double y = (Double) (p != null ? p.getValue() : null);
+ if (x == null || y == null) {
+ continue;
+ }
+ target.startTag(TAG_MARKER);
+ target.addAttribute("x", x.doubleValue());
+ target.addAttribute("y", y.doubleValue());
+ p = item.getItemProperty(getItemMarkerHtmlPropertyId());
+ final String h = (String) (p != null ? p.getValue() : null);
+ target.addAttribute("html", h);
+ target.endTag(TAG_MARKER);
+ }
+ target.endTag(TAG_MARKERS);
+ }
+ }
+
+ public void setZoomLevel(int zoomLevel) {
+ this.zoomLevel = zoomLevel;
+ requestRepaint();
+ }
+
+ public int getZoomLevel() {
+ return zoomLevel;
+ }
+
+ public void setMapCenter(Point2D.Double center) {
+ mapCenter = center;
+ }
+
+ public Point2D.Double getMapCenter() {
+ return mapCenter;
+ }
+
+ // Container.Viewer methods:
+
+ public Container getContainerDataSource() {
+ return dataSource;
+ }
+
+ public void setContainerDataSource(Container newDataSource) {
+
+ dataSource = newDataSource;
+
+ requestRepaint();
+ }
+
+ // Item methods
+
+ public Object getItemMarkerHtmlPropertyId() {
+ return itemMarkerHtmlPropertyId;
+ }
+
+ public void setItemMarkerHtmlPropertyId(Object itemMarkerHtmlPropertyId) {
+ this.itemMarkerHtmlPropertyId = itemMarkerHtmlPropertyId;
+ requestRepaint();
+ }
+
+ public Object getItemMarkerXPropertyId() {
+ return itemMarkerXPropertyId;
+ }
+
+ public void setItemMarkerXPropertyId(Object itemMarkerXPropertyId) {
+ this.itemMarkerXPropertyId = itemMarkerXPropertyId;
+ requestRepaint();
+ }
+
+ public Object getItemMarkerYPropertyId() {
+ return itemMarkerYPropertyId;
+ }
+
+ public void setItemMarkerYPropertyId(Object itemMarkerYPropertyId) {
+ this.itemMarkerYPropertyId = itemMarkerYPropertyId;
+ requestRepaint();
+ }
+
+ // Marker add
+
+ public Object addMarker(String html, Point2D.Double location) {
+ if (location == null) {
+ throw new IllegalArgumentException("Location must be non-null");
+ }
+ if (dataSource == null) {
+ initDataSource();
+ }
+ final Object markerId = dataSource.addItem();
+ if (markerId == null) {
+ return null;
+ }
+ final Item marker = dataSource.getItem(markerId);
+ Property p = marker.getItemProperty(getItemMarkerXPropertyId());
+ p.setValue(new Double(location.x));
+ p = marker.getItemProperty(getItemMarkerYPropertyId());
+ p.setValue(new Double(location.y));
+ p = marker.getItemProperty(getItemMarkerHtmlPropertyId());
+ p.setValue(html);
+
+ requestRepaint();
+
+ return markerId;
+ }
+
+ public void removeMarker(Object markerId) {
+ if (dataSource != null) {
+ dataSource.removeItem(markerId);
+ requestRepaint();
+ }
+ }
+
+ public Item getMarkerItem(Object markerId) {
+ if (dataSource != null) {
+ return dataSource.getItem(markerId);
+ } else {
+ return null;
+ }
+ }
+
+ // dataSource init helper:
+ private void initDataSource() {
+ dataSource = new IndexedContainer();
+ dataSource.addContainerProperty(itemMarkerHtmlPropertyId, String.class,
+ null);
+ dataSource.addContainerProperty(itemMarkerXPropertyId, Double.class,
+ new Double(0));
+ dataSource.addContainerProperty(itemMarkerYPropertyId, Double.class,
+ new Double(0));
+ }
+
+ public void clear() {
+ setContainerDataSource(null);
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/reservation/ReservationApplication.java b/src/com/vaadin/demo/reservation/ReservationApplication.java
new file mode 100644
index 0000000000..baba6c11a2
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/ReservationApplication.java
@@ -0,0 +1,335 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation;
+
+import java.awt.geom.Point2D;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.vaadin.Application;
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
+import com.vaadin.ui.Window.Notification;
+
+public class ReservationApplication extends Application {
+
+ private SampleDB db;
+
+ ResourceSelectorPanel resourcePanel;
+
+ private CalendarField reservedFrom;
+
+ private static final long DEFAULT_GAP_MILLIS = 3600000; // (almost) one
+
+ // hour
+ private long currentGapMillis = DEFAULT_GAP_MILLIS; // current length of
+
+ // reservation
+ private CalendarField reservedTo;
+
+ private Label resourceName;
+
+ private TextField description;
+
+ private Button reservationButton;
+
+ private Table allTable;
+
+ private GoogleMap map;
+
+ @Override
+ public void init() {
+ //
+ db = new SampleDB(getProperty("jdbcUrl"));
+
+ final Window mainWindow = new Window("Reservr ");
+ setMainWindow(mainWindow);
+ setTheme("reservr");
+ mainWindow.getLayout().setWidth("100%");
+
+ Label logo = new Label("Reservr");
+ logo.setStyleName("logo");
+ mainWindow.addComponent(logo);
+
+ Label slogan = new Label("Representational vehicles on-the-road");
+ slogan.setStyleName("slogan");
+ mainWindow.addComponent(slogan);
+
+ final TabSheet mainTabs = new TabSheet();
+ mainWindow.addComponent(mainTabs);
+
+ final OrderedLayout reservationTab = new OrderedLayout();
+ reservationTab.setWidth("100%");
+ mainTabs.addTab(reservationTab, "Make reservation", null);
+
+ resourcePanel = new ResourceSelectorPanel("Resources");
+ resourcePanel.setResourceContainer(db.getResources(null));
+ resourcePanel.addListener(
+ ResourceSelectorPanel.SelectedResourcesChangedEvent.class,
+ this, "selectedResourcesChanged");
+ reservationTab.addComponent(resourcePanel);
+
+ final Panel reservationPanel = new Panel("Reservation",
+ new OrderedLayout(OrderedLayout.ORIENTATION_HORIZONTAL));
+ reservationPanel.addStyleName(Panel.STYLE_LIGHT);
+ reservationPanel.getLayout().setMargin(true);
+ reservationTab.addComponent(reservationPanel);
+
+ final OrderedLayout infoLayout = new OrderedLayout();
+ infoLayout.setSpacing(true);
+ infoLayout.setSizeUndefined();
+ infoLayout.setMargin(false, true, false, false);
+ reservationPanel.addComponent(infoLayout);
+ resourceName = new Label("From the list above");
+ resourceName.setCaption("Choose resource");
+ infoLayout.addComponent(resourceName);
+ description = new TextField();
+ description.setWidth("250px");
+ description.setRows(5);
+ infoLayout.addComponent(description);
+ reservationButton = new Button("Make reservation", this,
+ "makeReservation");
+ infoLayout.addComponent(reservationButton);
+ infoLayout.setComponentAlignment(reservationButton, Alignment.MIDDLE_CENTER);
+
+ map = new GoogleMap();
+ map.setWidth("250px");
+ map.setHeight("250px");
+ map.setItemMarkerHtmlPropertyId(SampleDB.Resource.PROPERTY_ID_NAME);
+ map.setItemMarkerXPropertyId(SampleDB.Resource.PROPERTY_ID_LOCATIONX);
+ map.setItemMarkerYPropertyId(SampleDB.Resource.PROPERTY_ID_LOCATIONY);
+ map.setContainerDataSource(db.getResources(null));
+ infoLayout.addComponent(map);
+
+ final Calendar from = Calendar.getInstance();
+ from.add(Calendar.HOUR, 1);
+ from.set(Calendar.MINUTE, 0);
+ from.set(Calendar.SECOND, 0);
+ from.set(Calendar.MILLISECOND, 0);
+ reservedFrom = new CalendarField("From");
+ reservedFrom.setMinimumDate(from.getTime());
+ reservedFrom.setValue(from.getTime());
+ reservedFrom.setImmediate(true);
+ initCalendarFieldPropertyIds(reservedFrom);
+ reservationPanel.addComponent(reservedFrom);
+
+ final Label arrowLabel = new Label("&raquo;");
+ arrowLabel.setContentMode(Label.CONTENT_XHTML);
+ arrowLabel.setStyleName("arrow");
+ reservationPanel.addComponent(arrowLabel);
+
+ final Calendar to = Calendar.getInstance();
+ to.setTime(from.getTime());
+ to.add(Calendar.MILLISECOND, (int) DEFAULT_GAP_MILLIS);
+ reservedTo = new CalendarField("To");
+ reservedTo.setMinimumDate(to.getTime());
+ reservedTo.setValue(to.getTime());
+ reservedTo.setImmediate(true);
+ initCalendarFieldPropertyIds(reservedTo);
+ reservationPanel.addComponent(reservedTo);
+
+ reservedFrom.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ final Date fd = (Date) reservedFrom.getValue();
+ if (fd == null) {
+ reservedTo.setValue(null);
+ reservedTo.setEnabled(false);
+ refreshSelectedResources(true);
+ return;
+ } else {
+ reservedTo.setEnabled(true);
+ }
+ reservedTo.setMinimumDate(new Date(fd.getTime()
+ + DEFAULT_GAP_MILLIS));
+ final Calendar to = Calendar.getInstance();
+ to.setTime(fd);
+ to.add(Calendar.MILLISECOND, (int) currentGapMillis);
+ reservedTo.setValue(to.getTime());
+ refreshSelectedResources(true);
+ }
+ });
+ reservedTo.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ final Date from = (Date) reservedFrom.getValue();
+ final Date to = (Date) reservedTo.getValue();
+ currentGapMillis = to.getTime() - from.getTime();
+ if (currentGapMillis <= 0) {
+ final Calendar t = Calendar.getInstance();
+ t.setTime(from);
+ t.add(Calendar.MILLISECOND, (int) DEFAULT_GAP_MILLIS);
+ reservedTo.setValue(t.getTime());
+ }
+ refreshSelectedResources(true);
+ }
+ });
+
+ allTable = new Table();
+ allTable.setWidth("100%");
+ allTable.setHeight("450px");
+ allTable.setColumnCollapsingAllowed(true);
+ allTable.setColumnReorderingAllowed(true);
+ mainTabs.addTab(allTable, "All reservations", null);
+ mainTabs.addListener(new TabSheet.SelectedTabChangeListener() {
+ public void selectedTabChange(SelectedTabChangeEvent event) {
+ refreshReservations();
+ }
+ });
+
+ resourcePanel.selectFirstCategory();
+ refreshReservations();
+ refreshSelectedResources(true);
+ }
+
+ public void makeReservation() {
+ try {
+ final Item resource = getActiveResource();
+ if (resource != null) {
+ db.addReservation(resource, 0, (Date) reservedFrom.getValue(),
+ (Date) reservedTo.getValue(), (String) description
+ .getValue());
+ getMainWindow()
+ .showNotification(
+ "Success!",
+ "You have reserved the resource for the selected period.",
+ Notification.TYPE_WARNING_MESSAGE);
+ refreshReservations();
+ refreshSelectedResources(false);
+ } else {
+ getMainWindow().showNotification("Oops!",
+ "Please select a resource (or category) to reserve.",
+ Notification.TYPE_WARNING_MESSAGE);
+ }
+ } catch (final ResourceNotAvailableException e) {
+ getMainWindow()
+ .showNotification(
+ "Not available!",
+ "The selected resource is already reserved for the selected period.",
+ Notification.TYPE_ERROR_MESSAGE);
+ refreshReservations();
+ }
+ }
+
+ private Item getActiveResource() throws ResourceNotAvailableException {
+ final List rids = resourcePanel.getSelectedResources();
+ if (rids != null && rids.size() > 0) {
+ for (final Iterator it = rids.iterator(); it.hasNext();) {
+ final Item resource = (Item) it.next();
+ final int id = ((Integer) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_ID).getValue())
+ .intValue();
+ if (db.isAvailableResource(id, (Date) reservedFrom.getValue(),
+ (Date) reservedTo.getValue())) {
+ return resource;
+ }
+ }
+ throw new ResourceNotAvailableException("No available resources");
+ } else {
+ return null;
+ }
+ }
+
+ private void refreshReservations() {
+ final Container reservations = db.getReservations(resourcePanel
+ .getSelectedResources());
+ reservedFrom.setContainerDataSource(reservations);
+ reservedTo.setContainerDataSource(reservations);
+ final Container allReservations = db.getReservations(null);
+ allTable.setContainerDataSource(allReservations);
+ if (allReservations != null && allReservations.size() > 0) {
+ allTable.setVisibleColumns(new Object[] {
+ SampleDB.Reservation.PROPERTY_ID_RESERVED_FROM,
+ SampleDB.Reservation.PROPERTY_ID_RESERVED_TO,
+ SampleDB.Resource.PROPERTY_ID_NAME,
+ SampleDB.Resource.PROPERTY_ID_DESCRIPTION,
+ SampleDB.Reservation.PROPERTY_ID_DESCRIPTION });
+ allTable.setColumnHeaders(new String[] { "From", "To", "Resource",
+ "Description", "Message" });
+ }
+ }
+
+ private void refreshSelectedResources(boolean alertIfNotAvailable) {
+ Item resource = null;
+ try {
+ resource = getActiveResource();
+ } catch (final ResourceNotAvailableException e) {
+ if (alertIfNotAvailable) {
+ getMainWindow().showNotification("Not available",
+ "Please choose another resource or time period.",
+ Notification.TYPE_HUMANIZED_MESSAGE);
+ }
+ refreshReservations();
+ return;
+ }
+ map.clear();
+ if (resource == null) {
+ resourceName.setCaption("Choose resource above");
+ resourceName.setValue("");
+ map.setContainerDataSource(db.getResources(null));
+ map.setZoomLevel(1);
+
+ } else {
+ // Display active resource name + desc
+ String name = (String) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_NAME).getValue();
+ String desc = (String) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_DESCRIPTION).getValue();
+ resourceName.setCaption(name);
+ resourceName.setValue(desc);
+ // Put all resources on map (may be many if category was selected)
+ final LinkedList srs = resourcePanel.getSelectedResources();
+ for (final Iterator it = srs.iterator(); it.hasNext();) {
+ resource = (Item) it.next();
+ name = (String) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_NAME).getValue();
+ desc = (String) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_DESCRIPTION).getValue();
+ final Double x = (Double) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_LOCATIONX).getValue();
+ final Double y = (Double) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_LOCATIONY).getValue();
+ if (x != null && y != null) {
+ map.addMarker(name + "<br/>" + desc, new Point2D.Double(x
+ .doubleValue(), y.doubleValue()));
+
+ }
+
+ }
+ map.setZoomLevel((srs.size() == 1 ? 14 : 9));
+ }
+
+ }
+
+ private void initCalendarFieldPropertyIds(CalendarField cal) {
+ cal.setItemStyleNamePropertyId(SampleDB.Resource.PROPERTY_ID_STYLENAME);
+ cal
+ .setItemStartPropertyId(SampleDB.Reservation.PROPERTY_ID_RESERVED_FROM);
+ cal.setItemEndPropertyId(SampleDB.Reservation.PROPERTY_ID_RESERVED_TO);
+ cal.setItemTitlePropertyId(SampleDB.Resource.PROPERTY_ID_NAME);
+ cal
+ .setItemDescriptionPropertyId(SampleDB.Reservation.PROPERTY_ID_DESCRIPTION);
+ }
+
+ public void selectedResourcesChanged(
+ ResourceSelectorPanel.SelectedResourcesChangedEvent event) {
+ refreshReservations();
+ refreshSelectedResources(true);
+ }
+
+}
diff --git a/src/com/vaadin/demo/reservation/ResourceNotAvailableException.java b/src/com/vaadin/demo/reservation/ResourceNotAvailableException.java
new file mode 100644
index 0000000000..61e47b9153
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/ResourceNotAvailableException.java
@@ -0,0 +1,11 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation;
+
+public class ResourceNotAvailableException extends Exception {
+ public ResourceNotAvailableException(String message) {
+ super(message);
+ }
+}
diff --git a/src/com/vaadin/demo/reservation/ResourceSelectorPanel.java b/src/com/vaadin/demo/reservation/ResourceSelectorPanel.java
new file mode 100644
index 0000000000..d52f1ac84a
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/ResourceSelectorPanel.java
@@ -0,0 +1,140 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class ResourceSelectorPanel extends Panel implements
+ Button.ClickListener {
+ private final HashMap categoryLayouts = new HashMap();
+ private final HashMap categoryResources = new HashMap();
+
+ // private Container allResources;
+ private LinkedList selectedResources = null;
+
+ public ResourceSelectorPanel(String caption) {
+ super(caption, new OrderedLayout(OrderedLayout.ORIENTATION_HORIZONTAL));
+ addStyleName(Panel.STYLE_LIGHT);
+ setSizeUndefined();
+ setWidth("100%");
+ }
+
+ public void setResourceContainer(Container resources) {
+ removeAllComponents();
+ categoryLayouts.clear();
+ categoryResources.clear();
+ if (resources != null && resources.size() > 0) {
+ for (final Iterator it = resources.getItemIds().iterator(); it
+ .hasNext();) {
+ final Item resource = resources.getItem(it.next());
+ // final Integer id = (Integer) resource.getItemProperty(
+ // SampleDB.Resource.PROPERTY_ID_ID).getValue();
+ final String category = (String) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_CATEGORY).getValue();
+ final String name = (String) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_NAME).getValue();
+ final String description = (String) resource.getItemProperty(
+ SampleDB.Resource.PROPERTY_ID_DESCRIPTION).getValue();
+ final Button rButton = new Button(name, this);
+ rButton.setStyleName("link");
+ rButton.setDescription(description);
+ rButton.setData(resource);
+ Layout resourceLayout = (Layout) categoryLayouts.get(category);
+ LinkedList resourceList = (LinkedList) categoryResources
+ .get(category);
+ if (resourceLayout == null) {
+ resourceLayout = new OrderedLayout();
+ resourceLayout.setSizeUndefined();
+ resourceLayout.setMargin(true);
+ addComponent(resourceLayout);
+ categoryLayouts.put(category, resourceLayout);
+ resourceList = new LinkedList();
+ categoryResources.put(category, resourceList);
+ final Button cButton = new Button(category + " (any)", this);
+ cButton.setStyleName("important-link");
+ cButton.setData(category);
+ resourceLayout.addComponent(cButton);
+ }
+ resourceLayout.addComponent(rButton);
+ resourceList.add(resource);
+ }
+ }
+ }
+
+ // Selects one initial categore, inpractice randomly
+ public void selectFirstCategory() {
+ try {
+ final Object catId = categoryResources.keySet().iterator().next();
+ final LinkedList res = (LinkedList) categoryResources.get(catId);
+ final Layout l = (Layout) categoryLayouts.get(catId);
+ final Button catB = (Button) l.getComponentIterator().next();
+ setSelectedResources(res);
+ catB.setStyleName("selected-link");
+ } catch (final Exception e) {
+ e.printStackTrace(System.err);
+ }
+ }
+
+ private void setSelectedResources(LinkedList resources) {
+ selectedResources = resources;
+ fireEvent(new SelectedResourcesChangedEvent());
+ }
+
+ public LinkedList getSelectedResources() {
+ return selectedResources;
+ }
+
+ public void buttonClick(ClickEvent event) {
+ final Object source = event.getSource();
+ if (source instanceof Button) {
+ final Object data = ((Button) source).getData();
+ resetStyles();
+ if (data instanceof Item) {
+ final LinkedList rlist = new LinkedList();
+ rlist.add(data);
+ setSelectedResources(rlist);
+ } else {
+ final String category = (String) data;
+ final LinkedList resources = (LinkedList) categoryResources
+ .get(category);
+ setSelectedResources(resources);
+ }
+ ((Button) source).setStyleName("selected-link");
+ }
+
+ }
+
+ private void resetStyles() {
+ for (final Iterator it = categoryLayouts.values().iterator(); it
+ .hasNext();) {
+ final Layout lo = (Layout) it.next();
+ for (final Iterator bit = lo.getComponentIterator(); bit.hasNext();) {
+ final Button b = (Button) bit.next();
+ if (b.getData() instanceof Item) {
+ b.setStyleName("link");
+ } else {
+ b.setStyleName("important-link");
+ }
+ }
+ }
+
+ }
+
+ public class SelectedResourcesChangedEvent extends Event {
+ public SelectedResourcesChangedEvent() {
+ super(ResourceSelectorPanel.this);
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/reservation/SampleDB.java b/src/com/vaadin/demo/reservation/SampleDB.java
new file mode 100644
index 0000000000..225d4c767b
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/SampleDB.java
@@ -0,0 +1,558 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.QueryContainer;
+
+public class SampleDB {
+ public class User {
+ public static final String TABLE = "USER";
+ public static final String PROPERTY_ID_ID = TABLE + "_ID";
+ public static final String PROPERTY_ID_FULLNAME = TABLE + "_FULLNAME";
+ public static final String PROPERTY_ID_EMAIL = TABLE + "_EMAIL";
+ public static final String PROPERTY_ID_PASSWORD = TABLE + "_PASSWORD";
+ public static final String PROPERTY_ID_DELETED = TABLE + "_DELETED";
+ }
+
+ public class Resource {
+ public static final String TABLE = "RESOURCE";
+ public static final String PROPERTY_ID_ID = TABLE + "_ID";
+ public static final String PROPERTY_ID_STYLENAME = TABLE + "_STYLENAME";
+ public static final String PROPERTY_ID_NAME = TABLE + "_NAME";
+ public static final String PROPERTY_ID_DESCRIPTION = TABLE
+ + "_DESCRIPTION";
+ public static final String PROPERTY_ID_LOCATIONX = TABLE
+ + "_LOCATION_X";
+ public static final String PROPERTY_ID_LOCATIONY = TABLE
+ + "_LOCATION_Y";
+ public static final String PROPERTY_ID_CATEGORY = TABLE + "_CATEGORY";
+ public static final String PROPERTY_ID_DELETED = TABLE + "_DELETED";
+ }
+
+ public class Reservation {
+ public static final String TABLE = "RESERVATION";
+ public static final String PROPERTY_ID_ID = TABLE + "_ID";
+ public static final String PROPERTY_ID_DESCRIPTION = TABLE
+ + "_DESCRIPTION";
+ public static final String PROPERTY_ID_RESOURCE_ID = TABLE
+ + "_RESOURCE_ID";
+ public static final String PROPERTY_ID_RESERVED_BY_ID = TABLE
+ + "_RESERVED_BY_USER_ID";
+ public static final String PROPERTY_ID_RESERVED_FROM = TABLE
+ + "_RESERVED_FROM";
+ public static final String PROPERTY_ID_RESERVED_TO = TABLE
+ + "_RESERVED_TO";
+ }
+
+ private static final String DEFAULT_JDBC_URL = "jdbc:hsqldb:file:reservation.db";
+ private static Object dbMutex = new Object();
+
+ private static final String CREATE_TABLE_USER = "CREATE TABLE "
+ + User.TABLE + " (" + " " + User.PROPERTY_ID_ID
+ + " INTEGER IDENTITY" + ", " + User.PROPERTY_ID_FULLNAME
+ + " VARCHAR(100) NOT NULL" + ", " + User.PROPERTY_ID_EMAIL
+ + " VARCHAR(50) NOT NULL" + ", " + User.PROPERTY_ID_PASSWORD
+ + " VARCHAR(20) NOT NULL" + ", " + User.PROPERTY_ID_DELETED
+ + " BOOLEAN DEFAULT false NOT NULL" + ", UNIQUE("
+ + User.PROPERTY_ID_FULLNAME + "), UNIQUE(" + User.PROPERTY_ID_EMAIL
+ + ") )";
+ private static final String CREATE_TABLE_RESOURCE = "CREATE TABLE "
+ + Resource.TABLE + " (" + " " + Resource.PROPERTY_ID_ID
+ + " INTEGER IDENTITY" + ", " + Resource.PROPERTY_ID_STYLENAME
+ + " VARCHAR(20) NOT NULL" + ", " + Resource.PROPERTY_ID_NAME
+ + " VARCHAR(30) NOT NULL" + ", " + Resource.PROPERTY_ID_DESCRIPTION
+ + " VARCHAR(100)" + ", " + Resource.PROPERTY_ID_LOCATIONX
+ + " DOUBLE" + ", " + Resource.PROPERTY_ID_LOCATIONY + " DOUBLE"
+ + ", " + Resource.PROPERTY_ID_CATEGORY + " VARCHAR(30)" + ", "
+ + Resource.PROPERTY_ID_DELETED + " BOOLEAN DEFAULT false NOT NULL"
+ + ", UNIQUE(" + Resource.PROPERTY_ID_NAME + "))";
+ private static final String CREATE_TABLE_RESERVATION = "CREATE TABLE "
+ + Reservation.TABLE + " (" + " " + Reservation.PROPERTY_ID_ID
+ + " INTEGER IDENTITY" + ", " + Reservation.PROPERTY_ID_RESOURCE_ID
+ + " INTEGER" + ", " + Reservation.PROPERTY_ID_RESERVED_BY_ID
+ + " INTEGER" + ", " + Reservation.PROPERTY_ID_RESERVED_FROM
+ + " TIMESTAMP NOT NULL" + ", "
+ + Reservation.PROPERTY_ID_RESERVED_TO + " TIMESTAMP NOT NULL"
+ + ", " + Reservation.PROPERTY_ID_DESCRIPTION + " VARCHAR(100)"
+ + ", FOREIGN KEY (" + Reservation.PROPERTY_ID_RESOURCE_ID
+ + ") REFERENCES " + Resource.TABLE + "(" + Resource.PROPERTY_ID_ID
+ + "), FOREIGN KEY (" + Reservation.PROPERTY_ID_RESERVED_BY_ID
+ + ") REFERENCES " + User.TABLE + "(" + User.PROPERTY_ID_ID + "))";
+
+ private static Connection connection = null;
+
+ /**
+ * Create database.
+ *
+ * @param jdbcUrl
+ */
+ public SampleDB(String jdbcUrl) {
+ if (jdbcUrl == null || jdbcUrl.equals("")) {
+ jdbcUrl = DEFAULT_JDBC_URL;
+ }
+ // connect to SQL database
+ connect(jdbcUrl);
+
+ }
+
+ private synchronized void dropTables() {
+ try {
+ update("DROP TABLE " + Reservation.TABLE);
+ } catch (final SQLException IGNORED) {
+ // IGNORED, assuming it was not there
+ }
+ try {
+ update("DROP TABLE " + Resource.TABLE);
+ } catch (final SQLException IGNORED) {
+ // IGNORED, assuming it was not there
+ }
+ try {
+ update("DROP TABLE " + User.TABLE);
+ } catch (final SQLException IGNORED) {
+ // IGNORED, assuming it was not there
+ }
+ }
+
+ /**
+ * Connect to SQL database. In this sample we use HSQLDB and an toolkit
+ * named database in implicitly created into system memory.
+ *
+ */
+ private synchronized void connect(String dbUrl) {
+ if (connection == null) {
+ try {
+ Class.forName("org.hsqldb.jdbcDriver").newInstance();
+ connection = DriverManager.getConnection(dbUrl);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ dropTables();
+ // initialize SQL database
+ createTables();
+
+ // test by executing sample JDBC query
+ testDatabase();
+
+ generateResources();
+ generateDemoUser();
+ generateReservations();
+
+ }
+ }
+
+ /**
+ * use for SQL commands CREATE, DROP, INSERT and UPDATE
+ *
+ * @param expression
+ * @throws SQLException
+ */
+ private synchronized void update(String expression) throws SQLException {
+ Statement st = null;
+ st = connection.createStatement();
+ final int i = st.executeUpdate(expression);
+ if (i == -1) {
+ System.out.println("SampleDatabase error : " + expression);
+ }
+ st.close();
+ }
+
+ /**
+ * Create test table and few rows. Issue note: using capitalized column
+ * names as HSQLDB returns column names in capitalized form with this demo.
+ *
+ */
+ private synchronized void createTables() {
+ try {
+ String stmt = null;
+ stmt = CREATE_TABLE_RESOURCE;
+ update(stmt);
+ } catch (final SQLException e) {
+ if (e.toString().indexOf("Table already exists") == -1) {
+ throw new RuntimeException(e);
+ }
+ }
+ try {
+ String stmt = null;
+ stmt = CREATE_TABLE_USER;
+ update(stmt);
+ } catch (final SQLException e) {
+ if (e.toString().indexOf("Table already exists") == -1) {
+ throw new RuntimeException(e);
+ }
+ }
+ try {
+ String stmt = null;
+ stmt = CREATE_TABLE_RESERVATION;
+ update(stmt);
+ } catch (final SQLException e) {
+ if (e.toString().indexOf("Table already exists") == -1) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Test database connection with simple SELECT command.
+ *
+ */
+ private synchronized String testDatabase() {
+ String result = null;
+ try {
+ final Statement stmt = connection.createStatement(
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_UPDATABLE);
+ final ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM "
+ + Resource.TABLE);
+ rs.next();
+ result = "rowcount for table test is " + rs.getObject(1).toString();
+ stmt.close();
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ public Connection getConnection() {
+ return connection;
+ }
+
+ public Container getCategories() {
+ // TODO where deleted=?
+ final String q = "SELECT DISTINCT(" + Resource.PROPERTY_ID_CATEGORY
+ + ") FROM " + Resource.TABLE + " ORDER BY "
+ + Resource.PROPERTY_ID_CATEGORY;
+ try {
+ return new QueryContainer(q, connection,
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_READ_ONLY);
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public Container getResources(String category) {
+ // TODO where deleted=?
+ String q = "SELECT * FROM " + Resource.TABLE;
+ if (category != null) {
+ q += " WHERE " + Resource.PROPERTY_ID_CATEGORY + "='" + category
+ + "'"; // FIXME ->
+ // PreparedStatement!
+ }
+
+ try {
+ return new QueryContainer(q, connection,
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_READ_ONLY);
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public Container getReservations(List resources) {
+ // TODO where reserved_by=?
+ // TODO where from=?
+ // TODO where to=?
+ // TODO where deleted=?
+ String q = "SELECT * FROM " + Reservation.TABLE + "," + Resource.TABLE;
+ q += " WHERE " + Reservation.PROPERTY_ID_RESOURCE_ID + "="
+ + Resource.PROPERTY_ID_ID;
+ if (resources != null && resources.size() > 0) {
+ final StringBuffer s = new StringBuffer();
+ for (final Iterator it = resources.iterator(); it.hasNext();) {
+ if (s.length() > 0) {
+ s.append(",");
+ }
+ s.append(((Item) it.next())
+ .getItemProperty(Resource.PROPERTY_ID_ID));
+ }
+ q += " HAVING " + Reservation.PROPERTY_ID_RESOURCE_ID + " IN (" + s
+ + ")";
+ }
+ q += " ORDER BY " + Reservation.PROPERTY_ID_RESERVED_FROM;
+ try {
+ final QueryContainer qc = new QueryContainer(q, connection,
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_READ_ONLY);
+ if (qc.size() < 1) {
+ return null;
+ } else {
+ return qc;
+ }
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized void addReservation(Item resource, int reservedById,
+ Date reservedFrom, Date reservedTo, String description) {
+ if (reservedFrom.after(reservedTo)) {
+ final Date tmp = reservedTo;
+ reservedTo = reservedFrom;
+ reservedFrom = tmp;
+ }
+ final int resourceId = ((Integer) resource.getItemProperty(
+ Resource.PROPERTY_ID_ID).getValue()).intValue();
+ final String q = "INSERT INTO " + Reservation.TABLE + " ("
+ + Reservation.PROPERTY_ID_RESOURCE_ID + ","
+ + Reservation.PROPERTY_ID_RESERVED_BY_ID + ","
+ + Reservation.PROPERTY_ID_RESERVED_FROM + ","
+ + Reservation.PROPERTY_ID_RESERVED_TO + ","
+ + Reservation.PROPERTY_ID_DESCRIPTION + ")"
+ + "VALUES (?,?,?,?,?)";
+ synchronized (dbMutex) {
+ try {
+ if (!isAvailableResource(resourceId, reservedFrom, reservedTo)) {
+ throw new ResourceNotAvailableException(
+ "The resource is not available at that time.");
+ }
+ final PreparedStatement p = connection.prepareStatement(q);
+ p.setInt(1, resourceId);
+ p.setInt(2, reservedById);
+ p.setTimestamp(3,
+ new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(4, new java.sql.Timestamp(reservedTo.getTime()));
+ p.setString(5, description);
+ p.execute();
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public boolean isAvailableResource(int resourceId, Date reservedFrom,
+ Date reservedTo) {
+ // TODO where deleted=?
+ if (reservedFrom.after(reservedTo)) {
+ final Date tmp = reservedTo;
+ reservedTo = reservedFrom;
+ reservedFrom = tmp;
+ }
+ final String checkQ = "SELECT count(*) FROM " + Reservation.TABLE
+ + " WHERE " + Reservation.PROPERTY_ID_RESOURCE_ID + "=? AND (("
+ + Reservation.PROPERTY_ID_RESERVED_FROM + ">=? AND "
+ + Reservation.PROPERTY_ID_RESERVED_FROM + "<?) OR ("
+ + Reservation.PROPERTY_ID_RESERVED_TO + ">? AND "
+ + Reservation.PROPERTY_ID_RESERVED_TO + "<=?) OR ("
+ + Reservation.PROPERTY_ID_RESERVED_FROM + "<=? AND "
+ + Reservation.PROPERTY_ID_RESERVED_TO + ">=?)" + ")";
+ try {
+ final PreparedStatement p = connection.prepareStatement(checkQ);
+ p.setInt(1, resourceId);
+ p.setTimestamp(2, new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(3, new java.sql.Timestamp(reservedTo.getTime()));
+ p.setTimestamp(4, new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(5, new java.sql.Timestamp(reservedTo.getTime()));
+ p.setTimestamp(6, new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(7, new java.sql.Timestamp(reservedTo.getTime()));
+ p.execute();
+ final ResultSet rs = p.getResultSet();
+ if (rs.next() && rs.getInt(1) > 0) {
+ return false;
+ }
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+
+ public Container getUsers() {
+ // TODO where deleted=?
+ final String q = "SELECT * FROM " + User.TABLE + " ORDER BY "
+ + User.PROPERTY_ID_FULLNAME;
+ try {
+ final QueryContainer qc = new QueryContainer(q, connection,
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_READ_ONLY);
+ return qc;
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized void generateReservations() {
+ final int days = 30;
+ final String descriptions[] = { "Picking up guests from airport",
+ "Sightseeing with the guests",
+ "Moving new servers from A to B", "Shopping",
+ "Customer meeting", "Guests arriving at harbour",
+ "Moving furniture", "Taking guests to see town" };
+ final Container cat = getCategories();
+ final Collection cIds = cat.getItemIds();
+ for (final Iterator it = cIds.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ final Item ci = cat.getItem(id);
+ final String c = (String) ci.getItemProperty(
+ Resource.PROPERTY_ID_CATEGORY).getValue();
+ final Container resources = getResources(c);
+ final Collection rIds = resources.getItemIds();
+ final Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ final int hourNow = new Date().getHours();
+ // cal.add(Calendar.DAY_OF_MONTH, -days);
+ for (int i = 0; i < days; i++) {
+ int r = 3;
+ for (final Iterator rit = rIds.iterator(); rit.hasNext()
+ && r > 0; r--) {
+ final Object rid = rit.next();
+ final Item resource = resources.getItem(rid);
+ final int s = hourNow - 6
+ + (int) Math.round(Math.random() * 6.0);
+ final int e = s + 1 + (int) Math.round(Math.random() * 4.0);
+ final Date start = new Date(cal.getTimeInMillis());
+ start.setHours(s);
+ final Date end = new Date(cal.getTimeInMillis());
+ end.setHours(e);
+ addReservation(resource, 0, start, end,
+ descriptions[(int) Math.floor(Math.random()
+ * descriptions.length)]);
+ }
+ cal.add(Calendar.DATE, 1);
+ }
+ }
+
+ }
+
+ public synchronized void generateResources() {
+
+ final Object[][] resources = {
+ // Turku
+ { "01", "01 Ford Mondeo", "w/ company logo", "Turku",
+ new Double(60.510857), new Double(22.275424) },
+ { "02", "02 Citroen Jumper",
+ "w/ company logo. 12m3 storage space.", "Turku",
+ new Double(60.452171), new Double(22.2995) },
+ { "03", "03 Saab 93", "Cabriolet. Keys from the rental desk.",
+ "Turku", new Double(60.4507), new Double(22.295551) },
+ { "04", "04 Volvo S60", "Key from the rental desk.", "Turku",
+ new Double(60.434722), new Double(22.224398) },
+ { "05", "05 Smart fourtwo", "Cabrio. Keys from infodesk.",
+ "Turku", new Double(60.508970), new Double(22.264790) },
+ // Helsinki
+ { "06", "06 Smart fourtwo", "Cabrio. Keys from infodesk.",
+ "Helsinki", new Double(60.17175), new Double(24.939029) },
+ { "07", "07 Smart fourtwo", "Cabrio. Keys from infodesk.",
+ "Helsinki", new Double(60.17175), new Double(24.939029) },
+ { "08", "08 Smart fourtwo", "Cabrio. Keys from infodesk.",
+ "Helsinki", new Double(60.166579),
+ new Double(24.953899) },
+ { "09", "09 Volvo S60", "Keys from infodesk.", "Helsinki",
+ new Double(60.317832), new Double(24.967289) },
+ { "10", "10 Saab 93", "Keys from infodesk.", "Helsinki",
+ new Double(60.249193), new Double(25.045921) },
+ // Silicon Valley
+ { "11", "11 Ford Mustang", "Keys from Acme clerk.",
+ "Silicon Valley", new Double(37.615853),
+ new Double(-122.386384) },
+ { "12", "12 Ford Fusion", "Keys from infodesk.",
+ "Silicon Valley", new Double(37.365028),
+ new Double(-121.922654) },
+ { "13", "13 Land Rover", "Keys from infodesk.",
+ "Silicon Valley", new Double(37.365028),
+ new Double(-121.922654) },
+ { "14", "14 Land Rover", "Keys from infodesk.",
+ "Silicon Valley", new Double(37.365028),
+ new Double(-121.922654) },
+ { "15", "15 Ford Mustang", "GT Cal Special. Keys from guard.",
+ "Silicon Valley", new Double(37.403812),
+ new Double(-121.977425) },
+ { "16", "16 Ford Focus", "Keys from guard.", "Silicon Valley",
+ new Double(37.403812), new Double(-121.977425) },
+ // Paris
+ { "17", "17 Peugeot 308", "Keys from infodesk.", "Paris",
+ new Double(48.844756), new Double(2.372784) },
+ { "18", "18 Citroen C6", "Keys from rental desk.", "Paris",
+ new Double(49.007253), new Double(2.545025) },
+ { "19", "19 Citroen C6", "Keys from infodesk.", "Paris",
+ new Double(48.729061), new Double(2.368087) },
+ { "20", "20 Peugeot 308", "Keys from ticket sales.", "Paris",
+ new Double(48.880931), new Double(2.356988) },
+ { "21", "21 Peugeot 308", "Keys from ticket sales.", "Paris",
+ new Double(48.876479), new Double(2.358161) },
+ // STHLM
+ { "22", "22 Volvo S60", "Keys from infodesk.", "Stockholm",
+ new Double(59.350414), new Double(18.106574) },
+ { "23", "23 Saab 93", "Keys from infodesk.", "Stockholm",
+ new Double(59.355905), new Double(17.946784) },
+ { "24", "24 Smart fourtwo", "Keys from infodesk.", "Stockholm",
+ new Double(59.315939), new Double(18.095904) },
+ { "25", "25 Smart fourtwo", "Keys from infodesk.", "Stockholm",
+ new Double(59.330716), new Double(18.058702) },
+ // Boston
+ /*
+ * { "26", "26 Ford Mustang", "Keys from infodesk.", "Boston", new
+ * Double(42.366588), new Double(-71.020955) }, { "27", "27 Smart
+ * fourtwo", "Keys from infodesk.", "Boston", new Double(42.365419), new
+ * Double(-71.061748) }, { "28", "28 Volvo S60", "Keys from Seaport
+ * Hotel reception.", "Boston", new Double(42.34811), new
+ * Double(-71.041127) }, { "29", "29 Smart fourtwo", "Keys from Seaport
+ * Hotel reception.", "Boston", new Double(42.348072), new
+ * Double(-71.041315) },
+ */
+
+ };
+
+ final String q = "INSERT INTO " + Resource.TABLE + "("
+ + Resource.PROPERTY_ID_STYLENAME + ","
+ + Resource.PROPERTY_ID_NAME + ","
+ + Resource.PROPERTY_ID_DESCRIPTION + ","
+ + Resource.PROPERTY_ID_CATEGORY + ","
+ + Resource.PROPERTY_ID_LOCATIONX + ","
+ + Resource.PROPERTY_ID_LOCATIONY + ")"
+ + " VALUES (?,?,?,?,?,?)";
+ try {
+ final PreparedStatement stmt = connection.prepareStatement(q);
+ for (int i = 0; i < resources.length; i++) {
+ int j = 0;
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setDouble(j + 1, ((Double) resources[i][j++])
+ .doubleValue());
+ stmt.setDouble(j + 1, ((Double) resources[i][j++])
+ .doubleValue());
+ stmt.execute();
+ }
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized void generateDemoUser() {
+ final String q = "INSERT INTO USER (" + User.PROPERTY_ID_FULLNAME + ","
+ + User.PROPERTY_ID_EMAIL + "," + User.PROPERTY_ID_PASSWORD
+ + ") VALUES (?,?,?)";
+ try {
+ final PreparedStatement stmt = connection.prepareStatement(q);
+ stmt.setString(1, "Demo User");
+ stmt.setString(2, "demo.user@itmill.com");
+ stmt.setString(3, "demo");
+ stmt.execute();
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/reservation/gwt/ReservationWidgetSet.gwt.xml b/src/com/vaadin/demo/reservation/gwt/ReservationWidgetSet.gwt.xml
new file mode 100644
index 0000000000..8de74a3b9b
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/ReservationWidgetSet.gwt.xml
@@ -0,0 +1,29 @@
+<module>
+ <!-- Inherit DefaultWidgetSet -->
+ <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" />
+
+ <!-- The googlemaps_gwt module -->
+ <inherits name="com.google.gwt.maps.GoogleMaps" />
+
+ <!-- WidgetSet default theme -->
+ <stylesheet src="reservr/styles.css"/>
+
+ <!--
+ Google Maps needs an API key if you're not running this demo on "localhost".
+ You can get a Google Maps API key here:
+ http://www.google.com/apis/maps/signup.html
+
+ Append your Google Maps API key to the src -attribute below, like so:
+ src="http://maps.google.com/maps?gwt=1&amp;file=api&amp;v=2.x&key=XXXXXXXX"
+ where the X:s represent your key.
+ -->
+ <!-- Works w/o key for localhost:
+ <script src="http://maps.google.com/maps?gwt=1&amp;file=api&amp;v=2.x" />
+ -->
+ <!-- Using key for http://toolkit.itmill.com: -->
+ <script src="http://maps.google.com/maps?gwt=1&amp;file=api&amp;v=2.x&amp;key=ABQIAAAA4q5gw_y_N1Anvvn1KqbLwRTHuC2ERVOT66iQW8-FqpCQQUlHqBTZ0rGKdlKh9fxQOKN87TCwVNlIXQ" />
+
+ <!-- Entry point -->
+ <entry-point class="com.vaadin.demo.reservation.gwt.client.ReservationWidgetSet"/>
+
+</module>
diff --git a/src/com/vaadin/demo/reservation/gwt/client/ReservationWidgetSet.java b/src/com/vaadin/demo/reservation/gwt/client/ReservationWidgetSet.java
new file mode 100644
index 0000000000..9bf5f22061
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/client/ReservationWidgetSet.java
@@ -0,0 +1,37 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation.gwt.client;
+
+import com.vaadin.demo.reservation.gwt.client.ui.ICalendarField;
+import com.vaadin.demo.reservation.gwt.client.ui.IGoogleMap;
+import com.vaadin.terminal.gwt.client.DefaultWidgetSet;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class ReservationWidgetSet extends DefaultWidgetSet {
+ @Override
+ public Paintable createWidget(UIDL uidl) {
+ final Class type = resolveWidgetType(uidl);
+ if (IGoogleMap.class == type) {
+ return new IGoogleMap();
+ } else if (ICalendarField.class == type) {
+ return new ICalendarField();
+ }
+
+ return super.createWidget(uidl);
+ }
+
+ @Override
+ protected Class resolveWidgetType(UIDL uidl) {
+ final String tag = uidl.getTag();
+ if ("googlemap".equals(tag)) {
+ return IGoogleMap.class;
+ } else if ("calendarfield".equals(tag)) {
+ return ICalendarField.class;
+ }
+ return super.resolveWidgetType(uidl);
+ }
+
+}
diff --git a/src/com/vaadin/demo/reservation/gwt/client/ui/ICalendarField.java b/src/com/vaadin/demo/reservation/gwt/client/ui/ICalendarField.java
new file mode 100644
index 0000000000..a11321dfc0
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/client/ui/ICalendarField.java
@@ -0,0 +1,294 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.SourcesTableEvents;
+import com.google.gwt.user.client.ui.TableListener;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.DateTimeService;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.CalendarEntry;
+import com.vaadin.terminal.gwt.client.ui.ICalendarPanel;
+import com.vaadin.terminal.gwt.client.ui.IDateField;
+
+public class ICalendarField extends IDateField {
+
+ private final ICalendarPanel calPanel;
+
+ private SimplePanel hourPanel;
+
+ private FlexTable hourTable;
+
+ private final EntrySource entrySource;
+
+ private final TableListener ftListener = new HourTableListener();
+
+ private int realResolution = RESOLUTION_DAY;
+
+ private static final String CLASSNAME = IDateField.CLASSNAME
+ + "-entrycalendar";
+
+ public ICalendarField() {
+ super();
+ setStyleName(CLASSNAME);
+ calPanel = new ICalendarPanel(this);
+ add(calPanel);
+ entrySource = new EntrySource();
+ calPanel.setCalendarEntrySource(entrySource);
+ calPanel.addTableListener(new TableListener() {
+ public void onCellClicked(SourcesTableEvents sender, int row,
+ int cell) {
+ buildDayView(date);
+ }
+ });
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ super.updateFromUIDL(uidl, client);
+ // We want to draw our own hour list
+ realResolution = currentResolution;
+ currentResolution = RESOLUTION_DAY;
+ if (uidl.hasAttribute("min")) {
+ final String mins = uidl.getStringAttribute("min");
+ final long min = (mins != null ? Long.parseLong(mins) : 0);
+ final String maxs = uidl.getStringAttribute("max");
+ final long max = (maxs != null ? Long.parseLong(maxs) : 0);
+ final Date minDate = (min > 0 ? new Date(min) : null);
+ final Date maxDate = (max > 0 ? new Date(max) : null);
+ calPanel.setLimits(minDate, maxDate);
+ }
+ entrySource.clear();
+ for (final Iterator cit = uidl.getChildIterator(); cit.hasNext();) {
+ final UIDL child = (UIDL) cit.next();
+ if (child.getTag().equals("items")) {
+ for (final Iterator iit = child.getChildIterator(); iit
+ .hasNext();) {
+ final UIDL item = (UIDL) iit.next();
+ entrySource.addItem(item);
+ }
+ break;
+ }
+ }
+ calPanel.updateCalendar();
+ buildDayView(date);
+ }
+
+ protected void buildDayView(Date date) {
+ if (hourPanel == null) {
+ hourPanel = new SimplePanel();
+ hourPanel.setStyleName(CLASSNAME + "-hours");
+ calPanel.getFlexCellFormatter().setColSpan(8, 0, 7);
+ calPanel.setWidget(8, 0, hourPanel);
+ } else {
+ hourPanel.clear();
+ }
+ hourTable = new FlexTable();
+ hourTable.addTableListener(ftListener);
+ hourPanel.add(hourTable);
+ hourTable.setCellSpacing(1);
+
+ for (int i = 0; i < 24; i++) {
+ String style = (i % 2 == 0 ? "even" : "odd");
+ if (realResolution >= RESOLUTION_HOUR) {
+ if (this.date != null && this.date.getHours() == i) {
+ style = "selected";
+ }
+ }
+ hourTable.getRowFormatter().setStyleName(i,
+ CLASSNAME + "-row-" + style);
+ String hstr = (i < 10 ? "0" : "") + i + ":00";
+ if (dts.isTwelveHourClock()) {
+ final String ampm = (i < 12 ? "am" : "pm");
+ hstr = (i <= 12 ? i : i - 12) + ":00 " + ampm;
+ }
+ hourTable.setHTML(i, 0, "<span>" + hstr + "</span>");
+ hourTable.getCellFormatter()
+ .setStyleName(i, 0, CLASSNAME + "-time");
+ }
+
+ final List entries = entrySource.getEntries(date,
+ DateTimeService.RESOLUTION_DAY);
+ int currentCol = 1;
+ for (final Iterator it = entries.iterator(); it.hasNext();) {
+ final CalendarEntry entry = (CalendarEntry) it.next();
+ int start = 0;
+ int hours = 24;
+ if (!entry.isNotime()) {
+ Date d = entry.getStart();
+ // TODO consider month&year as well
+ start = (d.getDate() < date.getDate() ? 0 : d.getHours());
+ d = entry.getEnd();
+ hours = (d.getDate() > date.getDate() ? 24 : d.getHours())
+ - start;
+ if (hours < 1) {
+ // We can't draw entries smaller than
+ // one
+ hours = 1;
+ }
+ }
+ int col = currentCol;
+ if (col > 1) {
+ while (!hourTable.isCellPresent(start, col - 1)) {
+ col--;
+ }
+ }
+ hourTable.setHTML(start, col, "<span>"
+ + (entry.getTitle() != null ? entry.getTitle() : "&nbsp")
+ + "</span>");
+ hourTable.getFlexCellFormatter().setRowSpan(start, col, hours);
+ hourTable.getFlexCellFormatter().setStyleName(start, col,
+ CLASSNAME + "-entry");
+ final String sn = entry.getStyleName();
+ if (sn != null && !sn.equals("")) {
+ hourTable.getFlexCellFormatter().addStyleName(start, col,
+ CLASSNAME + "-" + entry.getStyleName());
+ }
+ final Element el = hourTable.getFlexCellFormatter().getElement(
+ start, col);
+
+ String tooltip;
+ if (DateTimeService.isSameDay(entry.getStart(), entry.getEnd())) {
+ tooltip = (start < 10 ? "0" : "") + start + ":00";
+ if (dts.isTwelveHourClock()) {
+ final String ampm = (start < 12 ? "am" : "pm");
+ tooltip = (start <= 12 ? start : start - 12) + ":00 "
+ + ampm;
+
+ }
+ tooltip += " (" + hours + "h) ";
+ if (entry.getTitle() != null) {
+ tooltip += entry.getTitle() + "\n ";
+ }
+ } else {
+ tooltip = entry.getStringForDate(entry.getEnd()) + "\n ";
+ }
+ if (entry.getDescription() != null) {
+ tooltip += "\"" + entry.getDescription() + "\"";
+ }
+ DOM.setElementProperty(el, "title", tooltip);
+
+ currentCol++;
+ }
+
+ // int hour = new Date().getHours()+1; // scroll to current hour
+ Date d = (this.date != null ? this.date : new Date());
+ final int hour = d.getHours() + 1; // scroll to selected
+ // hour
+ final int h1 = hourPanel.getOffsetHeight() / 2;
+ final int oh = hourTable.getOffsetHeight();
+ final int h2 = (int) (hour / 24.0 * oh);
+ final int scrollTop = h2 - h1;
+ final Element el = hourPanel.getElement();
+ setScrollTop(el, scrollTop);
+
+ }
+
+ private native void setScrollTop(Element el, int scrollTop)
+ /*-{
+ el.scrollTop = scrollTop;
+ }-*/;
+
+ private class HourTableListener implements TableListener {
+
+ public void onCellClicked(SourcesTableEvents sender, int row, int cell) {
+ if (realResolution < RESOLUTION_HOUR || date == null) {
+ return;
+ }
+ date.setHours(row);
+ client.updateVariable(id, "hour", row, immediate);
+ }
+
+ }
+
+ private class EntrySource implements ICalendarPanel.CalendarEntrySource {
+
+ private final HashMap dates = new HashMap();
+
+ public void addItem(UIDL item) {
+ final String styleName = item.getStringAttribute("styleName");
+ // final Integer id = new Integer(item.getIntAttribute("id"));
+
+ DateTimeFormat dtf = DateTimeFormat
+ .getFormat("d MM yyyy HH:mm:ss Z");
+
+ Date startDate = dtf.parse(item.getStringAttribute("start"));
+
+ // fix times with server-client difference
+ int diff = (startDate.getTimezoneOffset() - item
+ .getIntAttribute("Z")) * 60000;
+ startDate = new Date(startDate.getTime() + diff);
+ Date endDate;
+ if (item.hasAttribute("end")) {
+ endDate = dtf.parse(item.getStringAttribute("end"));
+ endDate = new Date(endDate.getTime() + diff);
+ } else {
+ endDate = (Date) startDate.clone();
+ }
+ final String title = item.getStringAttribute("title");
+ final String desc = item.getStringAttribute("description");
+ final boolean notime = item.getBooleanAttribute("notime");
+ final CalendarEntry entry = new CalendarEntry(styleName, startDate,
+ endDate, title, desc, notime);
+
+ // TODO should remove+readd if the same entry (id) is
+ // added again
+
+ for (final Date d = new Date(entry.getStart().getTime()); d
+ .getYear() <= entry.getEnd().getYear()
+ && d.getMonth() <= entry.getEnd().getYear()
+ && d.getDate() <= entry.getEnd().getDate(); d.setTime(d
+ .getTime() + 86400000)) {
+ final String key = d.getYear() + "" + d.getMonth() + ""
+ + d.getDate();
+ ArrayList l = (ArrayList) dates.get(key);
+ if (l == null) {
+ l = new ArrayList();
+ dates.put(key, l);
+ }
+ l.add(entry);
+ }
+ }
+
+ public List getEntries(Date date, int resolution) {
+ final ArrayList res = new ArrayList();
+ if (date == null) {
+ return res;
+ }
+ final List entries = (List) dates.get(date.getYear() + ""
+ + date.getMonth() + "" + date.getDate());
+
+ if (entries == null) {
+ return res;
+ }
+ for (final Iterator it = entries.iterator(); it.hasNext();) {
+ final CalendarEntry item = (CalendarEntry) it.next();
+ if (DateTimeService.isInRange(date, item.getStart(), item
+ .getEnd(), resolution)) {
+ res.add(item);
+ }
+ }
+
+ return res;
+ }
+
+ public void clear() {
+ dates.clear();
+ }
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/reservation/gwt/client/ui/IGoogleMap.java b/src/com/vaadin/demo/reservation/gwt/client/ui/IGoogleMap.java
new file mode 100644
index 0000000000..e69bcd16a9
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/client/ui/IGoogleMap.java
@@ -0,0 +1,91 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation.gwt.client.ui;
+
+import java.util.Iterator;
+
+import com.google.gwt.maps.client.InfoWindowContent;
+import com.google.gwt.maps.client.MapWidget;
+import com.google.gwt.maps.client.control.SmallMapControl;
+import com.google.gwt.maps.client.event.MarkerClickHandler;
+import com.google.gwt.maps.client.geom.LatLng;
+import com.google.gwt.maps.client.overlay.Marker;
+import com.google.gwt.user.client.ui.Composite;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class IGoogleMap extends Composite implements Paintable {
+
+ public static final String CLASSNAME = "i-googlemap";
+
+ private final MapWidget widget = new MapWidget();
+
+ public IGoogleMap() {
+ initWidget(widget);
+ setWidth("200px");
+ setHeight("200px");
+ setStyleName(CLASSNAME);
+ widget.addControl(new SmallMapControl());
+
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ widget.clearOverlays();
+ LatLng pos = null;
+ for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
+ final UIDL u = (UIDL) it.next();
+ if (u.getTag().equals("markers")) {
+
+ for (final Iterator m = u.getChildIterator(); m.hasNext();) {
+ final UIDL umarker = (UIDL) m.next();
+ final String html = "<span>"
+ + umarker.getStringAttribute("html") + "</span>";
+ final double x = umarker.getDoubleAttribute("x");
+ final double y = umarker.getDoubleAttribute("y");
+ pos = LatLng.newInstance(x, y);
+ final Marker marker = new Marker(pos);
+ widget.addOverlay(marker);
+ if (html != null) {
+ addMarkerPopup(marker, html);
+ }
+ }
+ }
+ }
+ if (uidl.hasAttribute("width")) {
+ widget.setWidth(uidl.getStringAttribute("width"));
+ }
+ if (uidl.hasAttribute("height")) {
+ widget.setHeight(uidl.getStringAttribute("height"));
+ }
+ if (uidl.hasAttribute("zoom")) {
+ widget.setZoomLevel(uidl.getIntAttribute("zoom"));
+ }
+ if (uidl.hasAttribute("centerX") && uidl.hasAttribute("centerY")) {
+ final LatLng center = LatLng.newInstance(uidl
+ .getDoubleAttribute("centerX"), uidl
+ .getDoubleAttribute("centerY"));
+ widget.setCenter(center);
+ } else if (pos != null) {
+ // use last marker position
+ widget.setCenter(pos);
+ }
+
+ }
+
+ private void addMarkerPopup(Marker marker, final String html) {
+ marker.addMarkerClickHandler(new MarkerClickHandler() {
+
+ public void onClick(MarkerClickEvent event) {
+ widget.getInfoWindow().open(event.getSender().getPoint(),
+ new InfoWindowContent(html));
+
+ }
+
+ });
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/reservation/gwt/public/reservr/googlemap/css/googlemap.css b/src/com/vaadin/demo/reservation/gwt/public/reservr/googlemap/css/googlemap.css
new file mode 100644
index 0000000000..306f4250f6
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/public/reservr/googlemap/css/googlemap.css
@@ -0,0 +1,4 @@
+.i-googlemap {
+ margin-top: 5px;
+ border: 1px solid #d6d6d6;
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/reservation/gwt/public/reservr/img/calendar-time-selected.gif b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/calendar-time-selected.gif
new file mode 100755
index 0000000000..73c7857fc9
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/calendar-time-selected.gif
Binary files differ
diff --git a/src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-bg.jpg b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-bg.jpg
new file mode 100644
index 0000000000..a6aeecaf70
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-bg.jpg
Binary files differ
diff --git a/src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-topleft.jpg b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-topleft.jpg
new file mode 100644
index 0000000000..53da0b13c0
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/entry-topleft.jpg
Binary files differ
diff --git a/src/com/vaadin/demo/reservation/gwt/public/reservr/img/event-bg.jpg b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/event-bg.jpg
new file mode 100644
index 0000000000..44d65c4dd7
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/public/reservr/img/event-bg.jpg
Binary files differ
diff --git a/src/com/vaadin/demo/reservation/gwt/public/reservr/styles.css b/src/com/vaadin/demo/reservation/gwt/public/reservr/styles.css
new file mode 100644
index 0000000000..14750f2869
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/gwt/public/reservr/styles.css
@@ -0,0 +1,149 @@
+@import "googlemap/css/googlemap.css";
+
+/* Entrycalendar styles */
+.i-datefield-entrycalendar-hours {
+ width: 240px;
+ height: auto;
+}
+.i-datefield-entrycalendar-hours table {
+ table-layout: fixed;
+}
+.i-datefield-entrycalendar-hours table tr {
+ height: 1em;
+}
+.i-datefield-entrycalendar-row-even {
+ cursor: pointer;
+ background: #fff;
+ height: 1em;
+}
+.i-datefield-entrycalendar-row-odd {
+ cursor: pointer;
+ background: #f6f7f7;
+ height: 1em;
+}
+.i-datefield-entrycalendar-row-selected {
+ color: #fff;
+ background: #5daee8 url(img/calendar-time-selected.gif) no-repeat;
+}
+.i-datefield-calendarpanel td.i-datefield-entrycalendar-time {
+ width: 55px;
+ padding: 2px 0px;
+ white-space: nowrap;
+}
+td.i-datefield-entrycalendar-time span {
+ width: 47px;
+ padding: 0px 4px;
+ text-align: right;
+ display: block;
+}
+td.i-datefield-entrycalendar-entry {
+ overflow: hidden;
+}
+td.i-datefield-entrycalendar-entry span {
+ display: block;
+ overflow: hidden;
+ padding: 2px;
+ color: #fff;
+ background-image: url(img/entry-topleft.jpg);
+ background-repeat: no-repeat;
+ background-position: 0px 0px;
+ text-align: left;
+}
+.i-datefield-calendarpanel td.i-datefield-entrycalendar-entry {
+ background-color: #F24C1A;
+ color: #fff;
+ background-image: url(img/entry-bg.jpg);
+ background-repeat: repeat-x;
+ vertical-align: top;
+ width: auto;
+}
+
+/* Reservr styles */
+.i-datefield-entrycalendar-01 {
+
+}
+.i-datefield-entrycalendar-02 {
+
+}
+.i-datefield-entrycalendar-03 {
+
+}
+.i-datefield-entrycalendar-04 {
+
+}
+.i-datefield-entrycalendar-05 {
+
+}
+.i-datefield-entrycalendar-06 {
+
+}
+.i-datefield-entrycalendar-07 {
+
+}
+.i-datefield-entrycalendar-08 {
+
+}
+.i-datefield-entrycalendar-09 {
+
+}
+.i-datefield-entrycalendar-10 {
+
+}
+.i-datefield-entrycalendar-11 {
+
+}
+.i-datefield-entrycalendar-12 {
+
+}
+.i-datefield-entrycalendar-13 {
+
+}
+.i-datefield-entrycalendar-14 {
+
+}
+.i-datefield-entrycalendar-15 {
+
+}
+.i-datefield-entrycalendar-16 {
+
+}
+.i-datefield-entrycalendar-17 {
+
+}
+.i-datefield-entrycalendar-18 {
+
+}
+.i-datefield-entrycalendar-19 {
+
+}
+.i-datefield-entrycalendar-20 {
+
+}
+.i-datefield-entrycalendar-21 {
+
+}
+.i-datefield-entrycalendar-22 {
+
+}
+.i-datefield-entrycalendar-23 {
+
+}
+.i-datefield-entrycalendar-24 {
+
+}
+.i-datefield-entrycalendar-25 {
+
+}
+.i-datefield-entrycalendar-26 {
+
+}
+.i-datefield-entrycalendar-27 {
+
+}
+.i-datefield-entrycalendar-28 {
+
+}
+.i-datefield-entrycalendar-29 {
+
+}
+
diff --git a/src/com/vaadin/demo/reservation/simple/AdminView.java b/src/com/vaadin/demo/reservation/simple/AdminView.java
new file mode 100644
index 0000000000..63b6f4c28c
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/simple/AdminView.java
@@ -0,0 +1,98 @@
+package com.vaadin.demo.reservation.simple;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.AbstractSelect.NewItemHandler;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+public class AdminView extends OrderedLayout {
+
+ private ComboBox resources = new ComboBox(
+ "Select for editing or type new resource");
+ private SimpleReserver application;
+ private OrderedLayout form = new OrderedLayout();
+ private Button save = new Button("Save resource");
+
+ private TextField name = new TextField("Name:");
+ private TextField desc = new TextField("Description:");
+ protected Item editedItem;
+
+ AdminView(SimpleReserver app) {
+ setWidth("250px");
+
+ application = app;
+
+ resources.setImmediate(true);
+ resources.setFilteringMode(ComboBox.FILTERINGMODE_CONTAINS);
+ refreshList();
+ resources.setItemCaptionMode(ComboBox.ITEM_CAPTION_MODE_PROPERTY);
+ resources.setItemCaptionPropertyId(SampleDB.Resource.PROPERTY_ID_NAME);
+ resources.setNewItemsAllowed(true);
+ resources.setNewItemHandler(new NewItemHandler() {
+ public void addNewItem(String newItemCaption) {
+ name.setValue(newItemCaption);
+ desc.setValue("");
+ form.setVisible(true);
+ }
+ });
+
+ resources.addListener(new ComboBox.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (resources.getValue() != null) {
+ editedItem = resources.getItem(resources.getValue());
+
+ name
+ .setPropertyDataSource(editedItem
+ .getItemProperty(SampleDB.Resource.PROPERTY_ID_NAME));
+ desc
+ .setPropertyDataSource(editedItem
+ .getItemProperty(SampleDB.Resource.PROPERTY_ID_DESCRIPTION));
+
+ form.setVisible(true);
+
+ } else {
+ form.setVisible(false);
+ editedItem = null;
+ }
+
+ }
+ });
+ addComponent(resources);
+
+ form.setVisible(false);
+ addComponent(form);
+ form.addComponent(name);
+ form.addComponent(desc);
+ name.setWidth("100%");
+ desc.setWidth("100%");
+ form.addComponent(save);
+ save.addListener(new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (editedItem == null) {
+ // save
+ int addResource = application.getDb().addResource(
+ name.getValue().toString(),
+ desc.getValue().toString());
+ } else {
+ // update
+ application.getDb().updateResource(editedItem,
+ name.getValue().toString(),
+ desc.getValue().toString());
+ }
+ resources.setValue(null);
+ refreshList();
+ }
+ });
+
+ }
+
+ private void refreshList() {
+ resources
+ .setContainerDataSource(application.getDb().getResources(null));
+ }
+}
diff --git a/src/com/vaadin/demo/reservation/simple/SampleDB.java b/src/com/vaadin/demo/reservation/simple/SampleDB.java
new file mode 100644
index 0000000000..dd0f5f7428
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/simple/SampleDB.java
@@ -0,0 +1,501 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.reservation.simple;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.QueryContainer;
+import com.vaadin.demo.reservation.ResourceNotAvailableException;
+
+/**
+ * Simplified version of Reservr's SampleDB
+ *
+ * If you are going to use this application in production, make sure to modify
+ * this to save data into real DB instead of in memory HSQLDB.
+ */
+public class SampleDB {
+
+ public class Resource {
+ public static final String TABLE = "RESOURCE";
+ public static final String PROPERTY_ID_ID = TABLE + "_ID";
+ public static final String PROPERTY_ID_STYLENAME = TABLE + "_STYLENAME";
+ public static final String PROPERTY_ID_NAME = TABLE + "_NAME";
+ public static final String PROPERTY_ID_DESCRIPTION = TABLE
+ + "_DESCRIPTION";
+ public static final String PROPERTY_ID_LOCATIONX = TABLE
+ + "_LOCATION_X";
+ public static final String PROPERTY_ID_LOCATIONY = TABLE
+ + "_LOCATION_Y";
+ public static final String PROPERTY_ID_CATEGORY = TABLE + "_CATEGORY";
+ public static final String PROPERTY_ID_DELETED = TABLE + "_DELETED";
+ }
+
+ public class Reservation {
+ public static final String TABLE = "RESERVATION";
+ public static final String PROPERTY_ID_ID = TABLE + "_ID";
+ public static final String PROPERTY_ID_DESCRIPTION = TABLE
+ + "_DESCRIPTION";
+ public static final String PROPERTY_ID_RESOURCE_ID = TABLE
+ + "_RESOURCE_ID";
+ public static final String PROPERTY_ID_RESERVED_BY = TABLE
+ + "_RESERVED_BY_USER";
+ public static final String PROPERTY_ID_RESERVED_FROM = TABLE
+ + "_RESERVED_FROM";
+ public static final String PROPERTY_ID_RESERVED_TO = TABLE
+ + "_RESERVED_TO";
+ }
+
+ // TODO -> param
+ private static final String DB_URL = "jdbc:hsqldb:file:reservationsimple.db";
+
+ private static final String CREATE_TABLE_RESOURCE = "CREATE TABLE "
+ + Resource.TABLE + " (" + " " + Resource.PROPERTY_ID_ID
+ + " INTEGER IDENTITY" + ", " + Resource.PROPERTY_ID_STYLENAME
+ + " VARCHAR(20) NOT NULL" + ", " + Resource.PROPERTY_ID_NAME
+ + " VARCHAR(30) NOT NULL" + ", " + Resource.PROPERTY_ID_DESCRIPTION
+ + " VARCHAR(100)" + ", " + Resource.PROPERTY_ID_LOCATIONX
+ + " DOUBLE" + ", " + Resource.PROPERTY_ID_LOCATIONY + " DOUBLE"
+ + ", " + Resource.PROPERTY_ID_CATEGORY + " VARCHAR(30)" + ", "
+ + Resource.PROPERTY_ID_DELETED + " BOOLEAN DEFAULT false NOT NULL"
+ + ", UNIQUE(" + Resource.PROPERTY_ID_NAME + "))";
+ private static final String CREATE_TABLE_RESERVATION = "CREATE TABLE "
+ + Reservation.TABLE + " (" + " " + Reservation.PROPERTY_ID_ID
+ + " INTEGER IDENTITY" + ", " + Reservation.PROPERTY_ID_RESOURCE_ID
+ + " INTEGER" + ", " + Reservation.PROPERTY_ID_RESERVED_FROM
+ + " TIMESTAMP NOT NULL" + ", "
+ + Reservation.PROPERTY_ID_RESERVED_TO + " TIMESTAMP NOT NULL"
+ + ", " + Reservation.PROPERTY_ID_DESCRIPTION + " VARCHAR(100)"
+ + ", " + Reservation.PROPERTY_ID_RESERVED_BY + " VARCHAR(100)"
+ + ", FOREIGN KEY (" + Reservation.PROPERTY_ID_RESOURCE_ID
+ + ") REFERENCES " + Resource.TABLE + "(" + Resource.PROPERTY_ID_ID
+ + "))";
+
+ private static Connection connection = null;
+
+ /**
+ * Create database.
+ */
+ public SampleDB() {
+ // connect to SQL database
+ connect();
+
+ }
+
+ private synchronized void dropTables() {
+ try {
+ update("DROP TABLE " + Reservation.TABLE);
+ } catch (final SQLException IGNORED) {
+ // IGNORED, assuming it was not there
+ }
+ try {
+ update("DROP TABLE " + Resource.TABLE);
+ } catch (final SQLException IGNORED) {
+ // IGNORED, assuming it was not there
+ }
+ }
+
+ /**
+ * Connect to SQL database. In this sample we use HSQLDB and an toolkit
+ * named database in implicitly created into system memory.
+ *
+ */
+ private synchronized void connect() {
+ if (connection == null) {
+ try {
+ Class.forName("org.hsqldb.jdbcDriver").newInstance();
+ connection = DriverManager.getConnection(DB_URL);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ dropTables();
+ // initialize SQL database
+ createTables();
+
+ // test by executing sample JDBC query
+ testDatabase();
+
+ generateResources();
+ generateReservations();
+
+ }
+ }
+
+ /**
+ * use for SQL commands CREATE, DROP, INSERT and UPDATE
+ *
+ * @param expression
+ * @throws SQLException
+ */
+ private synchronized void update(String expression) throws SQLException {
+ Statement st = null;
+ st = connection.createStatement();
+ final int i = st.executeUpdate(expression);
+ if (i == -1) {
+ System.out.println("SampleDatabase error : " + expression);
+ }
+ st.close();
+ }
+
+ /**
+ * Create test table and few rows. Issue note: using capitalized column
+ * names as HSQLDB returns column names in capitalized form with this demo.
+ *
+ */
+ private synchronized void createTables() {
+ try {
+ String stmt = null;
+ stmt = CREATE_TABLE_RESOURCE;
+ update(stmt);
+ } catch (final SQLException e) {
+ if (e.toString().indexOf("Table already exists") == -1) {
+ throw new RuntimeException(e);
+ }
+ }
+ try {
+ String stmt = null;
+ stmt = CREATE_TABLE_RESERVATION;
+ update(stmt);
+ } catch (final SQLException e) {
+ if (e.toString().indexOf("Table already exists") == -1) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Test database connection with simple SELECT command.
+ *
+ */
+ private synchronized String testDatabase() {
+ String result = null;
+ try {
+ final Statement stmt = connection.createStatement(
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_UPDATABLE);
+ final ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM "
+ + Resource.TABLE);
+ rs.next();
+ result = "rowcount for table test is " + rs.getObject(1).toString();
+ stmt.close();
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ public Connection getConnection() {
+ return connection;
+ }
+
+ public Container getCategories() {
+ // TODO where deleted=?
+ final String q = "SELECT DISTINCT(" + Resource.PROPERTY_ID_CATEGORY
+ + ") FROM " + Resource.TABLE + " ORDER BY "
+ + Resource.PROPERTY_ID_CATEGORY;
+ try {
+ return new QueryContainer(q, connection,
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_READ_ONLY);
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public Container getResources(String category) {
+ // TODO where deleted=?
+ String q = "SELECT * FROM " + Resource.TABLE;
+ if (category != null) {
+ q += " WHERE " + Resource.PROPERTY_ID_CATEGORY + "='" + category
+ + "'"; // FIXME ->
+ // PreparedStatement!
+ }
+
+ try {
+ return new QueryContainer(q, connection,
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_READ_ONLY);
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public Container getReservations(List resources) {
+ // TODO where reserved_by=?
+ // TODO where from=?
+ // TODO where to=?
+ // TODO where deleted=?
+ String q = "SELECT * FROM " + Reservation.TABLE + "," + Resource.TABLE;
+ q += " WHERE " + Reservation.PROPERTY_ID_RESOURCE_ID + "="
+ + Resource.PROPERTY_ID_ID;
+ if (resources != null && resources.size() > 0) {
+ final StringBuffer s = new StringBuffer();
+ for (final Iterator it = resources.iterator(); it.hasNext();) {
+ if (s.length() > 0) {
+ s.append(",");
+ }
+ s.append(((Item) it.next())
+ .getItemProperty(Resource.PROPERTY_ID_ID));
+ }
+ q += " HAVING " + Reservation.PROPERTY_ID_RESOURCE_ID + " IN (" + s
+ + ")";
+ }
+ q += " ORDER BY " + Reservation.PROPERTY_ID_RESERVED_FROM;
+ try {
+ final QueryContainer qc = new QueryContainer(q, connection,
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_READ_ONLY);
+ if (qc.size() < 1) {
+ return null;
+ } else {
+ return qc;
+ }
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized void addReservation(Item resource, String reservedBy,
+ Date reservedFrom, Date reservedTo, String description)
+ throws ResourceNotAvailableException {
+ if (reservedFrom.after(reservedTo)) {
+ final Date tmp = reservedTo;
+ reservedTo = reservedFrom;
+ reservedFrom = tmp;
+ }
+ final int resourceId = ((Integer) resource.getItemProperty(
+ Resource.PROPERTY_ID_ID).getValue()).intValue();
+ final String q = "INSERT INTO " + Reservation.TABLE + " ("
+ + Reservation.PROPERTY_ID_RESOURCE_ID + ","
+ + Reservation.PROPERTY_ID_RESERVED_BY + ","
+ + Reservation.PROPERTY_ID_RESERVED_FROM + ","
+ + Reservation.PROPERTY_ID_RESERVED_TO + ","
+ + Reservation.PROPERTY_ID_DESCRIPTION + ")"
+ + "VALUES (?,?,?,?,?)";
+ synchronized (DB_URL) {
+ if (!isAvailableResource(resourceId, reservedFrom, reservedTo)) {
+ throw new ResourceNotAvailableException(
+ "The resource is not available at that time.");
+ }
+ try {
+ PreparedStatement p;
+ p = connection.prepareStatement(q);
+ p.setInt(1, resourceId);
+ p.setString(2, reservedBy);
+ p.setTimestamp(3,
+ new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(4, new java.sql.Timestamp(reservedTo.getTime()));
+ p.setString(5, description);
+ p.execute();
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public boolean isAvailableResource(int resourceId, Date reservedFrom,
+ Date reservedTo) {
+ // TODO where deleted=?
+ if (reservedFrom.after(reservedTo)) {
+ final Date tmp = reservedTo;
+ reservedTo = reservedFrom;
+ reservedFrom = tmp;
+ }
+ final String checkQ = "SELECT count(*) FROM " + Reservation.TABLE
+ + " WHERE " + Reservation.PROPERTY_ID_RESOURCE_ID + "=? AND (("
+ + Reservation.PROPERTY_ID_RESERVED_FROM + ">=? AND "
+ + Reservation.PROPERTY_ID_RESERVED_FROM + "<?) OR ("
+ + Reservation.PROPERTY_ID_RESERVED_TO + ">? AND "
+ + Reservation.PROPERTY_ID_RESERVED_TO + "<=?) OR ("
+ + Reservation.PROPERTY_ID_RESERVED_FROM + "<=? AND "
+ + Reservation.PROPERTY_ID_RESERVED_TO + ">=?)" + ")";
+ try {
+ final PreparedStatement p = connection.prepareStatement(checkQ);
+ p.setInt(1, resourceId);
+ p.setTimestamp(2, new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(3, new java.sql.Timestamp(reservedTo.getTime()));
+ p.setTimestamp(4, new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(5, new java.sql.Timestamp(reservedTo.getTime()));
+ p.setTimestamp(6, new java.sql.Timestamp(reservedFrom.getTime()));
+ p.setTimestamp(7, new java.sql.Timestamp(reservedTo.getTime()));
+ p.execute();
+ final ResultSet rs = p.getResultSet();
+ if (rs.next() && rs.getInt(1) > 0) {
+ return false;
+ }
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+
+ public synchronized void generateReservations() {
+ final int days = 30;
+ final String descriptions[] = { "Picking up guests from airport",
+ "Sightseeing with the guests",
+ "Moving new servers from A to B", "Shopping",
+ "Customer meeting", "Guests arriving at harbour",
+ "Moving furniture", "Taking guests to see town" };
+ final Container cat = getCategories();
+ final Collection cIds = cat.getItemIds();
+ for (final Iterator it = cIds.iterator(); it.hasNext();) {
+ final Object id = it.next();
+ final Item ci = cat.getItem(id);
+ final String c = (String) ci.getItemProperty(
+ Resource.PROPERTY_ID_CATEGORY).getValue();
+ final Container resources = getResources(c);
+ final Collection rIds = resources.getItemIds();
+ final Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ final int hourNow = new Date().getHours();
+ // cal.add(Calendar.DAY_OF_MONTH, -days);
+ for (int i = 0; i < days; i++) {
+ int r = 3;
+ for (final Iterator rit = rIds.iterator(); rit.hasNext()
+ && r > 0; r--) {
+ final Object rid = rit.next();
+ final Item resource = resources.getItem(rid);
+ final int s = hourNow - 6
+ + (int) Math.round(Math.random() * 6.0);
+ final int e = s + 1 + (int) Math.round(Math.random() * 4.0);
+ final Date start = new Date(cal.getTimeInMillis());
+ start.setHours(s);
+ final Date end = new Date(cal.getTimeInMillis());
+ end.setHours(e);
+ try {
+ addReservation(resource, "Demo User", start, end,
+ descriptions[(int) Math.floor(Math.random()
+ * descriptions.length)]);
+ } catch (ResourceNotAvailableException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+ cal.add(Calendar.DATE, 1);
+ }
+ }
+
+ }
+
+ public synchronized void generateResources() {
+
+ final Object[][] resources = {
+
+ { "01", "Portable Video projector 1", "Small,XGA resolution",
+ "Turku", new Double(60.510857), new Double(22.275424) },
+ { "02", "Auditorio", "", "Turku", new Double(60.452171),
+ new Double(22.2995) },
+ { "03", "Meeting room 1", "Projector, WiFi", "Turku",
+ new Double(60.4507), new Double(22.295551) },
+ { "04", "Meeting room 2", "WiFi, Blackboard", "Turku",
+ new Double(60.434722), new Double(22.224398) },
+ { "05", "AV Room", "Cabrio. Keys from infodesk.", "Turku",
+ new Double(60.508970), new Double(22.264790) },
+ { "06", "Video projector",
+ "Rather heavy, good luminance, WXGA", "Turku",
+ new Double(60.434722), new Double(22.224398) },
+
+ };
+
+ final String q = "INSERT INTO " + Resource.TABLE + "("
+ + Resource.PROPERTY_ID_STYLENAME + ","
+ + Resource.PROPERTY_ID_NAME + ","
+ + Resource.PROPERTY_ID_DESCRIPTION + ","
+ + Resource.PROPERTY_ID_CATEGORY + ","
+ + Resource.PROPERTY_ID_LOCATIONX + ","
+ + Resource.PROPERTY_ID_LOCATIONY + ")"
+ + " VALUES (?,?,?,?,?,?)";
+ try {
+ final PreparedStatement stmt = connection.prepareStatement(q);
+ for (int i = 0; i < resources.length; i++) {
+ int j = 0;
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setString(j + 1, (String) resources[i][j++]);
+ stmt.setDouble(j + 1, ((Double) resources[i][j++])
+ .doubleValue());
+ stmt.setDouble(j + 1, ((Double) resources[i][j++])
+ .doubleValue());
+ stmt.execute();
+ }
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int addResource(String name, String desc) {
+ final String q = "INSERT INTO " + Resource.TABLE + " ("
+ + Resource.PROPERTY_ID_STYLENAME + ","
+ + Resource.PROPERTY_ID_NAME + ","
+ + Resource.PROPERTY_ID_DESCRIPTION + ","
+ + Resource.PROPERTY_ID_CATEGORY + ","
+ + Resource.PROPERTY_ID_LOCATIONX + ","
+ + Resource.PROPERTY_ID_LOCATIONY + ")"
+ + " VALUES (?,?,?,?,?,?)";
+ synchronized (DB_URL) {
+ try {
+ PreparedStatement p = connection.prepareStatement(q);
+ p.setString(1, "");
+ p.setString(2, name);
+ p.setString(3, desc);
+ p.setString(4, "default");
+ p.setDouble(5, 0);
+ p.setDouble(6, 0);
+ p.execute();
+
+ Statement createStatement = connection.createStatement();
+ ResultSet executeQuery = createStatement
+ .executeQuery("CALL IDENTITY()");
+ executeQuery.next();
+ return executeQuery.getInt(1);
+
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ return -1;
+ }
+
+ public void updateResource(Item editedItem, String name, String desc) {
+ final String q = "UPDATE " + Resource.TABLE + " SET "
+ + Resource.PROPERTY_ID_NAME + " = ? ,"
+ + Resource.PROPERTY_ID_DESCRIPTION + " = ? " + "WHERE "
+ + Resource.PROPERTY_ID_ID + " = ?";
+ synchronized (DB_URL) {
+ try {
+ PreparedStatement p = connection.prepareStatement(q);
+ p.setString(1, name);
+ p.setString(2, desc);
+ p.setInt(3, ((Integer) editedItem.getItemProperty(
+ Resource.PROPERTY_ID_ID).getValue()).intValue());
+ p.execute();
+
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ }
+}
diff --git a/src/com/vaadin/demo/reservation/simple/SimpleReserver.java b/src/com/vaadin/demo/reservation/simple/SimpleReserver.java
new file mode 100644
index 0000000000..25c2ec0bd0
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/simple/SimpleReserver.java
@@ -0,0 +1,134 @@
+package com.vaadin.demo.reservation.simple;
+
+import java.security.Principal;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.PortletMode;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+
+import com.liferay.portal.model.User;
+import com.liferay.portal.service.UserServiceUtil;
+import com.vaadin.Application;
+import com.vaadin.terminal.gwt.server.PortletApplicationContext;
+import com.vaadin.terminal.gwt.server.PortletApplicationContext.PortletListener;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+/**
+ * This is a stripped down version of Reservr example. Idea is to create simple,
+ * but actually usable portal gadget. Example is Liferay spesific (in user
+ * handling), so you need to add portal-kernel.jar and portal-service.jar files
+ * to your classpath.
+ *
+ */
+public class SimpleReserver extends Application {
+
+ private SampleDB db = new SampleDB();
+
+ private StdView stdView = new StdView(this);
+
+ private AdminView adminView = new AdminView(this);
+
+ private Button toggleMode = new Button("Switch mode");
+
+ private boolean isAdminView = false;
+
+ private boolean isPortlet;
+
+ protected User user;
+
+ @Override
+ public void init() {
+ final Window w = new Window("Simple Reserver");
+ w.addStyleName("simplereserver");
+
+ if (getContext() instanceof PortletApplicationContext) {
+ isPortlet = true;
+ PortletApplicationContext context = (PortletApplicationContext) getContext();
+ context.addPortletListener(this, new PortletListener() {
+
+ public void handleActionRequest(ActionRequest request,
+ ActionResponse response) {
+
+ }
+
+ public void handleRenderRequest(RenderRequest request,
+ RenderResponse response) {
+ // react on mode changes
+ if ((request.getPortletMode() == PortletMode.EDIT && !isAdminView)
+ || (request.getPortletMode() == PortletMode.VIEW && isAdminView)) {
+ toggleMode();
+ }
+
+ // save user object to application for later use
+ Principal userPrincipal = request.getUserPrincipal();
+ try {
+ user = UserServiceUtil.getUserById(Long
+ .parseLong(userPrincipal.toString()));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+ });
+ w.setTheme("liferay");
+ // portal will deal outer margins
+ w.getLayout().setMargin(false);
+ } else {
+ w.setTheme("reservr");
+ }
+
+ setMainWindow(w);
+ if (!isPortlet) {
+ // only use toggle mode button when not in portal
+ w.addComponent(toggleMode);
+ toggleMode.addListener(new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ toggleMode();
+ }
+ });
+ }
+ w.addComponent(stdView);
+ }
+
+ protected void toggleMode() {
+ OrderedLayout main = (OrderedLayout) getMainWindow().getLayout();
+ isAdminView = !isAdminView;
+ if (isAdminView) {
+ main.replaceComponent(stdView, adminView);
+ } else {
+ main.replaceComponent(adminView, stdView);
+ stdView.refreshData();
+ }
+ }
+
+ public SampleDB getDb() {
+ return db;
+ }
+
+ @Override
+ public Object getUser() {
+ if (getContext() instanceof PortletApplicationContext) {
+ try {
+ return user.getFirstName() + " " + user.getLastName();
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ return "Portlet Demouser";
+ }
+ } else {
+ Object user = super.getUser();
+ if (user == null) {
+ return "Demo User";
+ } else {
+ return user;
+ }
+ }
+
+ }
+}
diff --git a/src/com/vaadin/demo/reservation/simple/StdView.java b/src/com/vaadin/demo/reservation/simple/StdView.java
new file mode 100644
index 0000000000..b9699bbbed
--- /dev/null
+++ b/src/com/vaadin/demo/reservation/simple/StdView.java
@@ -0,0 +1,194 @@
+package com.vaadin.demo.reservation.simple;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.demo.reservation.CalendarField;
+import com.vaadin.demo.reservation.ResourceNotAvailableException;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.OrderedLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+public class StdView extends OrderedLayout {
+
+ private ComboBox resources = new ComboBox("Select resource");
+ private CalendarField reservations = new CalendarField();
+ private Button add = new Button("Add reservation");
+ private SimpleReserver application;
+
+ private EditorWindow editor = new EditorWindow();
+
+ StdView(SimpleReserver app) {
+ setWidth("250px");
+ application = app;
+
+ resources.setImmediate(true);
+ resources.setFilteringMode(ComboBox.FILTERINGMODE_CONTAINS);
+ resources
+ .setContainerDataSource(application.getDb().getResources(null));
+ resources.setItemCaptionMode(ComboBox.ITEM_CAPTION_MODE_PROPERTY);
+ resources.setItemCaptionPropertyId(SampleDB.Resource.PROPERTY_ID_NAME);
+ resources.addListener(new ComboBox.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ refreshReservations();
+ }
+ });
+ addComponent(resources);
+
+ initCalendarFieldPropertyIds(reservations);
+ Calendar c = Calendar.getInstance();
+ reservations.setValue(c.getTime());
+ reservations.setEnabled(false);
+ addComponent(reservations);
+ reservations.setImmediate(true);
+
+ add.setEnabled(false);
+ addComponent(add);
+
+ add.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (resources.getValue() != null) {
+ Item i = resources.getItem(resources.getValue());
+ editor.newReservationFor(i);
+ }
+ }
+ });
+
+ add.setDescription("Add new reservation for selected resource");
+
+ }
+
+ private static void initCalendarFieldPropertyIds(CalendarField cal) {
+ cal.setItemStyleNamePropertyId(SampleDB.Resource.PROPERTY_ID_STYLENAME);
+ cal
+ .setItemStartPropertyId(SampleDB.Reservation.PROPERTY_ID_RESERVED_FROM);
+ cal.setItemEndPropertyId(SampleDB.Reservation.PROPERTY_ID_RESERVED_TO);
+ cal
+ .setItemTitlePropertyId(SampleDB.Reservation.PROPERTY_ID_RESERVED_BY);
+ cal
+ .setItemDescriptionPropertyId(SampleDB.Reservation.PROPERTY_ID_DESCRIPTION);
+ }
+
+ private void refreshReservations() {
+ if (resources.getValue() == null) {
+ reservations.setContainerDataSource(null);
+ add.setEnabled(false);
+ reservations.setEnabled(false);
+ } else {
+ List resource = new LinkedList();
+ resource.add(resources.getItem(resources.getValue()));
+ final Container res = application.getDb().getReservations(resource);
+ reservations.setContainerDataSource(res);
+ add.setEnabled(true);
+ reservations.setEnabled(true);
+ }
+ }
+
+ public class EditorWindow extends Window {
+
+ Label resourceName = new Label();
+
+ DateField start = new DateField("From:");
+ DateField end = new DateField("To:");
+ TextField desc = new TextField("Description:");
+ Button save = new Button("Save");
+
+ private Item res;
+
+ private Calendar cal;
+
+ EditorWindow() {
+ super("Add reservation");
+
+ cal = Calendar.getInstance();
+
+ addComponent(resourceName);
+
+ start.setResolution(DateField.RESOLUTION_MIN);
+ start.setImmediate(true);
+ start.setValue(new Date());
+ start.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ Date startTime = (Date) start.getValue();
+ Date endTime = (Date) end.getValue();
+ if (endTime.before(startTime)) {
+ cal.setTime(startTime);
+ cal.add(Calendar.HOUR_OF_DAY, 1);
+ end.setValue(cal.getTime());
+ }
+ }
+ });
+ addComponent(start);
+
+ end.setResolution(DateField.RESOLUTION_MIN);
+ end.setImmediate(true);
+ end.setValue(new Date());
+ end.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ Date startTime = (Date) start.getValue();
+ Date endTime = (Date) end.getValue();
+ if (endTime.before(startTime)) {
+ cal.setTime(endTime);
+ cal.add(Calendar.HOUR, -1);
+ start.setValue(cal.getTime());
+ }
+ }
+ });
+ addComponent(end);
+ addComponent(desc);
+ addComponent(save);
+ save.addListener(new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ try {
+ application.getDb().addReservation(res,
+ application.getUser().toString(),
+ (Date) start.getValue(), (Date) end.getValue(),
+ (String) desc.getValue());
+ EditorWindow.this.close();
+ refreshReservations();
+ } catch (ResourceNotAvailableException e) {
+ getWindow()
+ .showNotification(
+ "Resource is not available at that time "
+ + "or is too close to another reservation.");
+ }
+ }
+ });
+ }
+
+ public void newReservationFor(Item resource) {
+ res = resource;
+ resourceName.setValue("Resourse: "
+ + res.getItemProperty(SampleDB.Resource.PROPERTY_ID_NAME)
+ .getValue());
+
+ cal.setTime((Date) reservations.getValue());
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ cal.set(Calendar.SECOND, 0);
+ start.setValue(cal.getTime());
+ cal.add(Calendar.HOUR_OF_DAY, 1);
+ end.setValue(cal.getTime());
+ StdView.this.getWindow().addWindow(this);
+ }
+ }
+
+ public void refreshData() {
+ resources
+ .setContainerDataSource(application.getDb().getResources(null));
+ refreshReservations();
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/APIResource.java b/src/com/vaadin/demo/sampler/APIResource.java
new file mode 100644
index 0000000000..f7138aac12
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/APIResource.java
@@ -0,0 +1,57 @@
+package com.vaadin.demo.sampler;
+
+/**
+ * A NamedExternalResource pointing to the javadoc for the given class. Knows
+ * where the javadocs are located for some common APIs, but one can also specify
+ * a javadoc baseurl. The name will be set to the class simpleName.
+ *
+ */
+public class APIResource extends NamedExternalResource {
+
+ private static final String ITMILL_BASE = "http://toolkit.itmill.com/demo/doc/api/";
+ private static final String JAVA_BASE = "http://java.sun.com/javase/6/docs/api/";
+ private static final String SERVLET_BASE = "http://java.sun.com/products/servlet/2.5/docs/servlet-2_5-mr2";
+ private static final String PORTLET_BASE = "http://developers.sun.com/docs/jscreator/apis/portlet";
+
+ public APIResource(Class clazz) {
+ this(resolveBaseUrl(clazz), clazz);
+ }
+
+ public APIResource(String baseUrl, Class clazz) {
+ super(resolveName(clazz), getJavadocUrl(baseUrl, clazz));
+ }
+
+ private static String getJavadocUrl(String baseUrl, Class clazz) {
+ if (!baseUrl.endsWith("/")) {
+ baseUrl += "/";
+ }
+ String path = clazz.getName().replaceAll("\\.", "/");
+ path = path.replaceAll("\\$", ".");
+ return baseUrl + path + ".html";
+ }
+
+ /**
+ * Tries to resolve the javadoc baseurl for the given class by looking at
+ * the packagename.
+ *
+ * @param clazz
+ * @return
+ */
+ private static String resolveBaseUrl(Class clazz) {
+ String name = clazz.getName();
+ if (name.startsWith("javax.servlet.")) {
+ return SERVLET_BASE;
+ } else if (name.startsWith("javax.portlet.")) {
+ return PORTLET_BASE;
+ } else if (name.startsWith("java.") || name.startsWith("javax.")) {
+ return JAVA_BASE;
+ }
+ return ITMILL_BASE;
+ }
+
+ private static String resolveName(Class clazz) {
+ Class ec = clazz.getEnclosingClass();
+ return (ec != null ? ec.getSimpleName() + "." : "")
+ + clazz.getSimpleName();
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/ActiveLink.java b/src/com/vaadin/demo/sampler/ActiveLink.java
new file mode 100644
index 0000000000..375728aafc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/ActiveLink.java
@@ -0,0 +1,164 @@
+package com.vaadin.demo.sampler;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Map;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Resource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+@SuppressWarnings("serial")
+public class ActiveLink extends Link {
+
+ private static final String TAG = "activelink";
+
+ private static final Method LINK_FOLLOWED_METHOD;
+
+ private HashSet listeners = new HashSet();
+
+ public ActiveLink() {
+ super();
+ }
+
+ public ActiveLink(String caption, Resource resource, String targetName,
+ int width, int height, int border) {
+ super(caption, resource, targetName, width, height, border);
+ }
+
+ public ActiveLink(String caption, Resource resource) {
+ super(caption, resource);
+ }
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
+ static {
+ try {
+ LINK_FOLLOWED_METHOD = LinkActivatedListener.class
+ .getDeclaredMethod("linkActivated",
+ new Class[] { LinkActivatedEvent.class });
+ } catch (final java.lang.NoSuchMethodException e) {
+ // This should never happen
+ throw new java.lang.RuntimeException(
+ "Internal error finding methods in ActiveLink");
+ }
+ }
+
+ /**
+ * Adds the link activated listener.
+ *
+ * @param listener
+ * the Listener to be added.
+ */
+ public void addListener(LinkActivatedListener listener) {
+ listeners.add(listener);
+ addListener(LinkActivatedEvent.class, listener, LINK_FOLLOWED_METHOD);
+ if (listeners.size() == 1) {
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Removes the link activated listener.
+ *
+ * @param listener
+ * the Listener to be removed.
+ */
+ public void removeListener(ClickListener listener) {
+ listeners.remove(listener);
+ removeListener(ClickEvent.class, listener, LINK_FOLLOWED_METHOD);
+ if (listeners.size() == 0) {
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Emits the options change event.
+ */
+ protected void fireClick(boolean linkOpened) {
+ fireEvent(new LinkActivatedEvent(this, linkOpened));
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+
+ if (listeners.size() > 0) {
+ target.addVariable(this, "activated", false);
+ target.addVariable(this, "opened", false);
+ }
+ }
+
+ @Override
+ public void changeVariables(Object source, Map variables) {
+ super.changeVariables(source, variables);
+ if (!isReadOnly() && variables.containsKey("activated")) {
+ final Boolean activated = (Boolean) variables.get("activated");
+ final Boolean opened = (Boolean) variables.get("opened");
+ if (activated != null && activated.booleanValue() && !isReadOnly()) {
+ fireClick((opened != null && opened.booleanValue() ? true
+ : false));
+ }
+ }
+ }
+
+ public class LinkActivatedEvent extends Component.Event {
+
+ private boolean linkOpened;
+
+ /**
+ * New instance of text change event.
+ *
+ * @param source
+ * the Source of the event.
+ */
+ public LinkActivatedEvent(Component source, boolean linkOpened) {
+ super(source);
+ this.linkOpened = linkOpened;
+ }
+
+ /**
+ * Gets the ActiveLink where the event occurred.
+ *
+ * @return the Source of the event.
+ */
+ public ActiveLink getActiveLink() {
+ return (ActiveLink) getSource();
+ }
+
+ /**
+ * Indicates whether or not the link was opened on the client, i.e in a
+ * new window/tab. If the link was not opened, the listener should react
+ * to the event and "do something", otherwise the link does nothing.
+ *
+ * @return true if the link was opened on the client
+ */
+ public boolean isLinkOpened() {
+ return linkOpened;
+ }
+ }
+
+ /**
+ * ActiveLink click listener
+ */
+ public interface LinkActivatedListener extends Serializable {
+
+ /**
+ * ActiveLink has been activated.
+ *
+ * @param event
+ * ActiveLink click event.
+ */
+ public void linkActivated(LinkActivatedEvent event);
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/CodeLabel.java b/src/com/vaadin/demo/sampler/CodeLabel.java
new file mode 100644
index 0000000000..fba8a8ac9f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/CodeLabel.java
@@ -0,0 +1,31 @@
+package com.vaadin.demo.sampler;
+
+import com.vaadin.ui.Label;
+
+public class CodeLabel extends Label {
+
+ private static final String TAG = "codelabel";
+
+ public CodeLabel() {
+ setContentMode(CONTENT_PREFORMATTED);
+ }
+
+ public CodeLabel(String content) {
+ super(content, CONTENT_PREFORMATTED);
+ }
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
+ @Override
+ public void setContentMode(int contentMode) {
+ if (contentMode != CONTENT_PREFORMATTED) {
+ throw new UnsupportedOperationException(
+ "Only preformatted content supported");
+ }
+ super.setContentMode(CONTENT_PREFORMATTED);
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/ExampleUtil.java b/src/com/vaadin/demo/sampler/ExampleUtil.java
new file mode 100644
index 0000000000..3888dd25fa
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/ExampleUtil.java
@@ -0,0 +1,242 @@
+package com.vaadin.demo.sampler;
+
+import java.util.Locale;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.ThemeResource;
+
+public final class ExampleUtil {
+ public static final String lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ut massa eget erat dapibus sollicitudin. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque a augue. Praesent non elit. Duis sapien dolor, cursus eget, pulvinar eget, eleifend a, est. Integer in nunc. Vivamus consequat ipsum id sapien. Duis eu elit vel libero posuere luctus. Aliquam ac turpis. Aenean vitae justo in sem iaculis pulvinar. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam sit amet mi. "
+ + "<br/>"
+ + "Aenean auctor, mi sit amet ultricies pulvinar, dui urna adipiscing odio, ut faucibus odio mauris eget justo. Mauris quis magna quis augue interdum porttitor. Sed interdum, tortor laoreet tincidunt ullamcorper, metus velit hendrerit nunc, id laoreet mauris arcu vitae est. Nulla nec nisl. Mauris orci nibh, tempor nec, sollicitudin ac, venenatis sed, lorem. Quisque dignissim tempus erat. Maecenas molestie, pede ac ultrices interdum, felis neque vulputate quam, in sodales felis odio quis mi. Aliquam massa pede, pharetra quis, tincidunt quis, fringilla at, mauris. Vestibulum a massa. Vestibulum luctus odio ut quam. Maecenas congue convallis diam. Cras urna arcu, vestibulum vitae, blandit ut, laoreet id, risus. Ut condimentum, arcu sit amet placerat blandit, augue nibh pretium nunc, in tempus sem dolor non leo. Etiam fringilla mauris a odio. Nunc lorem diam, interdum eget, lacinia in, scelerisque sit amet, purus. Nam ornare. "
+ + "<br/>"
+ + "Donec placerat dui ut orci. Phasellus quis lacus at nisl elementum cursus. Cras bibendum egestas nulla. Phasellus pulvinar ullamcorper odio. Etiam ipsum. Proin tincidunt. Aliquam aliquet. Etiam purus odio, commodo sed, feugiat volutpat, scelerisque molestie, velit. Aenean sed sem sit amet libero sodales ultrices. Donec dictum, arcu sed iaculis porttitor, est mauris pulvinar purus, sit amet porta purus neque in risus. Mauris libero. Maecenas rhoncus. Morbi quis nisl. "
+ + "<br/>"
+ + "Vestibulum laoreet tortor eu elit. Cras euismod nulla eu sapien. Sed imperdiet. Maecenas vel sapien. Nulla at purus eu diam auctor lobortis. Donec pede eros, lacinia tincidunt, tempus eu, molestie nec, velit. Nullam ipsum odio, euismod non, aliquet nec, consequat ac, felis. Duis fermentum mauris sed justo. Suspendisse potenti. Praesent at libero sit amet ipsum imperdiet fermentum. Aliquam enim nisl, dictum id, lacinia sit amet, elementum posuere, ipsum. Integer luctus dictum libero. Pellentesque sed pede sed nisl bibendum porttitor. Phasellus tempor interdum nisi. Mauris nec magna. Phasellus massa pede, vehicula sed, ornare at, ullamcorper ut, nisl. Sed turpis nisl, hendrerit sit amet, consequat id, auctor nec, arcu. Quisque fringilla tincidunt massa. In eleifend, nulla sed mollis vestibulum, mauris orci facilisis ante, id pharetra dolor ipsum vitae sem. Integer dictum. "
+ + "<br/>"
+ + "Nunc ut odio. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mauris tellus, dapibus vel, hendrerit vel, sollicitudin ut, ligula. Ut justo metus, accumsan placerat, ultrices sit amet, congue at, nulla. Integer in quam. Cras sollicitudin mattis magna. Vestibulum neque eros, egestas ut, tincidunt vel, ullamcorper non, ligula. Vivamus eu lacus. Donec rhoncus metus et odio. Donec est. Nulla facilisi. Suspendisse potenti. Etiam tempor pede nec ante. Vestibulum adipiscing velit vel neque. "
+ + "<br/>"
+ + "Quisque ornare erat rhoncus lectus. Donec vitae ante at enim mollis egestas. Mauris convallis. Fusce convallis, nisl eu sagittis suscipit, risus ligula aliquam libero, in imperdiet neque mi non risus. Aenean dictum ultricies risus. Praesent ut ligula vitae purus ornare auctor. Cras tellus mauris, adipiscing ac, dignissim auctor, faucibus in, sem. Cras mauris libero, pharetra sit amet, lacinia eu, vehicula eleifend, sapien. Donec ac tellus. Sed eros dui, vulputate vel, auctor pharetra, tincidunt at, ipsum. Duis at dolor ac leo condimentum pulvinar. Donec molestie, dolor et fringilla elementum, nibh nibh iaculis orci, eu elementum odio turpis et odio. Phasellus fermentum, justo id placerat egestas, arcu nunc molestie ante, non imperdiet ligula lectus sed erat. Quisque sed ligula. Sed ac nulla. Nullam massa. "
+ + "<br/>"
+ + "Sed a purus. Mauris non nibh blandit neque cursus scelerisque. Quisque ultrices sem nec dolor. Donec non diam ut dui consequat venenatis. Nullam risus massa, egestas in, facilisis tristique, molestie sed, mi. Duis euismod turpis sit amet quam. Vestibulum ornare felis eget dolor. Phasellus ac urna vel sapien lacinia adipiscing. Donec egestas felis id mi. Sed erat. Vestibulum porta vulputate neque. Maecenas scelerisque, sem id sodales pretium, sem mauris rhoncus magna, at scelerisque tortor mauris nec dui. Nullam blandit rhoncus velit. Nam accumsan, enim id vestibulum feugiat, lorem nibh placerat urna, eget laoreet diam tortor at lorem. Suspendisse imperdiet consectetur dolor. ";
+ private static final String[] iso3166 = new String[] { "AFGHANISTAN", "AF",
+ "Ã…LAND ISLANDS", "AX", "ALBANIA", "AL", "ALGERIA", "DZ",
+ "AMERICAN SAMOA", "AS", "ANDORRA", "AD", "ANGOLA", "AO",
+ "ANGUILLA", "AI", "ANTARCTICA", "AQ", "ANTIGUA AND BARBUDA", "AG",
+ "ARGENTINA", "AR", "ARMENIA", "AM", "ARUBA", "AW", "AUSTRALIA",
+ "AU", "AUSTRIA", "AT", "AZERBAIJAN", "AZ", "BAHAMAS", "BS",
+ "BAHRAIN", "BH", "BANGLADESH", "BD", "BARBADOS", "BB", "BELARUS",
+ "BY", "BELGIUM", "BE", "BELIZE", "BZ", "BENIN", "BJ", "BERMUDA",
+ "BM", "BHUTAN", "BT", "BOLIVIA", "BO", "BOSNIA AND HERZEGOVINA",
+ "BA", "BOTSWANA", "BW", "BOUVET ISLAND", "BV", "BRAZIL", "BR",
+ "BRITISH INDIAN OCEAN TERRITORY", "IO", "BRUNEI DARUSSALAM", "BN",
+ "BULGARIA", "BG", "BURKINA FASO", "BF", "BURUNDI", "BI",
+ "CAMBODIA", "KH", "CAMEROON", "CM", "CANADA", "CA", "CAPE VERDE",
+ "CV", "CAYMAN ISLANDS", "KY", "CENTRAL AFRICAN REPUBLIC", "CF",
+ "CHAD", "TD", "CHILE", "CL", "CHINA", "CN", "CHRISTMAS ISLAND",
+ "CX", "COCOS (KEELING) ISLANDS", "CC", "COLOMBIA", "CO", "COMOROS",
+ "KM", "CONGO", "CG", "CONGO, THE DEMOCRATIC REPUBLIC OF THE", "CD",
+ "COOK ISLANDS", "CK", "COSTA RICA", "CR", "CÔTE D'IVOIRE", "CI",
+ "CROATIA", "HR", "CUBA", "CU", "CYPRUS", "CY", "CZECH REPUBLIC",
+ "CZ", "DENMARK", "DK", "DJIBOUTI", "DJ", "DOMINICA", "DM",
+ "DOMINICAN REPUBLIC", "DO", "ECUADOR", "EC", "EGYPT", "EG",
+ "EL SALVADOR", "SV", "EQUATORIAL GUINEA", "GQ", "ERITREA", "ER",
+ "ESTONIA", "EE", "ETHIOPIA", "ET", "FALKLAND ISLANDS (MALVINAS)",
+ "FK", "FAROE ISLANDS", "FO", "FIJI", "FJ", "FINLAND", "FI",
+ "FRANCE", "FR", "FRENCH GUIANA", "GF", "FRENCH POLYNESIA", "PF",
+ "FRENCH SOUTHERN TERRITORIES", "TF", "GABON", "GA", "GAMBIA", "GM",
+ "GEORGIA", "GE", "GERMANY", "DE", "GHANA", "GH", "GIBRALTAR", "GI",
+ "GREECE", "GR", "GREENLAND", "GL", "GRENADA", "GD", "GUADELOUPE",
+ "GP", "GUAM", "GU", "GUATEMALA", "GT", "GUERNSEY", "GG", "GUINEA",
+ "GN", "GUINEA-BISSAU", "GW", "GUYANA", "GY", "HAITI", "HT",
+ "HEARD ISLAND AND MCDONALD ISLANDS", "HM",
+ "HOLY SEE (VATICAN CITY STATE)", "VA", "HONDURAS", "HN",
+ "HONG KONG", "HK", "HUNGARY", "HU", "ICELAND", "IS", "INDIA", "IN",
+ "INDONESIA", "ID", "IRAN, ISLAMIC REPUBLIC OF", "IR", "IRAQ", "IQ",
+ "IRELAND", "IE", "ISLE OF MAN", "IM", "ISRAEL", "IL", "ITALY",
+ "IT", "JAMAICA", "JM", "JAPAN", "JP", "JERSEY", "JE", "JORDAN",
+ "JO", "KAZAKHSTAN", "KZ", "KENYA", "KE", "KIRIBATI", "KI",
+ "KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF", "KP",
+ "KOREA, REPUBLIC OF", "KR", "KUWAIT", "KW", "KYRGYZSTAN", "KG",
+ "LAO PEOPLE'S DEMOCRATIC REPUBLIC", "LA", "LATVIA", "LV",
+ "LEBANON", "LB", "LESOTHO", "LS", "LIBERIA", "LR",
+ "LIBYAN ARAB JAMAHIRIYA", "LY", "LIECHTENSTEIN", "LI", "LITHUANIA",
+ "LT", "LUXEMBOURG", "LU", "MACAO", "MO",
+ "MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF", "MK", "MADAGASCAR",
+ "MG", "MALAWI", "MW", "MALAYSIA", "MY", "MALDIVES", "MV", "MALI",
+ "ML", "MALTA", "MT", "MARSHALL ISLANDS", "MH", "MARTINIQUE", "MQ",
+ "MAURITANIA", "MR", "MAURITIUS", "MU", "MAYOTTE", "YT", "MEXICO",
+ "MX", "MICRONESIA, FEDERATED STATES OF", "FM",
+ "MOLDOVA, REPUBLIC OF", "MD", "MONACO", "MC", "MONGOLIA", "MN",
+ "MONTENEGRO", "ME", "MONTSERRAT", "MS", "MOROCCO", "MA",
+ "MOZAMBIQUE", "MZ", "MYANMAR", "MM", "NAMIBIA", "NA", "NAURU",
+ "NR", "NEPAL", "NP", "NETHERLANDS", "NL", "NETHERLANDS ANTILLES",
+ "AN", "NEW CALEDONIA", "NC", "NEW ZEALAND", "NZ", "NICARAGUA",
+ "NI", "NIGER", "NE", "NIGERIA", "NG", "NIUE", "NU",
+ "NORFOLK ISLAND", "NF", "NORTHERN MARIANA ISLANDS", "MP", "NORWAY",
+ "NO", "OMAN", "OM", "PAKISTAN", "PK", "PALAU", "PW",
+ "PALESTINIAN TERRITORY, OCCUPIED", "PS", "PANAMA", "PA",
+ "PAPUA NEW GUINEA", "PG", "PARAGUAY", "PY", "PERU", "PE",
+ "PHILIPPINES", "PH", "PITCAIRN", "PN", "POLAND", "PL", "PORTUGAL",
+ "PT", "PUERTO RICO", "PR", "QATAR", "QA", "REUNION", "RE",
+ "ROMANIA", "RO", "RUSSIAN FEDERATION", "RU", "RWANDA", "RW",
+ "SAINT BARTHÉLEMY", "BL", "SAINT HELENA", "SH",
+ "SAINT KITTS AND NEVIS", "KN", "SAINT LUCIA", "LC", "SAINT MARTIN",
+ "MF", "SAINT PIERRE AND MIQUELON", "PM",
+ "SAINT VINCENT AND THE GRENADINES", "VC", "SAMOA", "WS",
+ "SAN MARINO", "SM", "SAO TOME AND PRINCIPE", "ST", "SAUDI ARABIA",
+ "SA", "SENEGAL", "SN", "SERBIA", "RS", "SEYCHELLES", "SC",
+ "SIERRA LEONE", "SL", "SINGAPORE", "SG", "SLOVAKIA", "SK",
+ "SLOVENIA", "SI", "SOLOMON ISLANDS", "SB", "SOMALIA", "SO",
+ "SOUTH AFRICA", "ZA",
+ "SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS", "GS", "SPAIN",
+ "ES", "SRI LANKA", "LK", "SUDAN", "SD", "SURINAME", "SR",
+ "SVALBARD AND JAN MAYEN", "SJ", "SWAZILAND", "SZ", "SWEDEN", "SE",
+ "SWITZERLAND", "CH", "SYRIAN ARAB REPUBLIC", "SY",
+ "TAIWAN, PROVINCE OF CHINA", "TW", "TAJIKISTAN", "TJ",
+ "TANZANIA, UNITED REPUBLIC OF", "TZ", "THAILAND", "TH",
+ "TIMOR-LESTE", "TL", "TOGO", "TG", "TOKELAU", "TK", "TONGA", "TO",
+ "TRINIDAD AND TOBAGO", "TT", "TUNISIA", "TN", "TURKEY", "TR",
+ "TURKMENISTAN", "TM", "TURKS AND CAICOS ISLANDS", "TC", "TUVALU",
+ "TV", "UGANDA", "UG", "UKRAINE", "UA", "UNITED ARAB EMIRATES",
+ "AE", "UNITED KINGDOM", "GB", "UNITED STATES", "US",
+ "UNITED STATES MINOR OUTLYING ISLANDS", "UM", "URUGUAY", "UY",
+ "UZBEKISTAN", "UZ", "VANUATU", "VU", "VENEZUELA", "VE", "VIET NAM",
+ "VN", "VIRGIN ISLANDS, BRITISH", "VG", "VIRGIN ISLANDS, U.S.",
+ "VI", "WALLIS AND FUTUNA", "WF", "WESTERN SAHARA", "EH", "YEMEN",
+ "YE", "ZAMBIA", "ZM", "ZIMBABWE", "ZW" };
+ public static final Object iso3166_PROPERTY_NAME = "name";
+ public static final Object iso3166_PROPERTY_SHORT = "short";
+ public static final Object iso3166_PROPERTY_FLAG = "flag";
+ public static final Object hw_PROPERTY_NAME = "name";
+
+ public static final Object locale_PROPERTY_LOCALE = "locale";
+ public static final Object locale_PROPERTY_NAME = "name";
+ private static final String[][] locales = { { "fi", "FI", "Finnish" },
+ { "de", "DE", "German" }, { "en", "US", "US - English" },
+ { "sv", "SE", "Swedish" } };
+ private static final String[][] hardware = { //
+ { "Desktops", "Dell OptiPlex GX240", "Dell OptiPlex GX260",
+ "Dell OptiPlex GX280" },
+ { "Monitors", "Benq T190HD", "Benq T220HD", "Benq T240HD" },
+ { "Laptops", "IBM ThinkPad T40", "IBM ThinkPad T43",
+ "IBM ThinkPad T60" } };
+
+ public static final Object PERSON_PROPERTY_FIRSTNAME = "First Name";
+ public static final Object PERSON_PROPERTY_LASTNAME = "Last Name";
+ private static final String[] firstnames = new String[] { "John", "Mary",
+ "Joe", "Sarah", "Jeff", "Jane", "Peter", "Marc", "Robert", "Paula",
+ "Lenny", "Kenny", "Nathan", "Nicole", "Laura", "Jos", "Josie",
+ "Linus" };
+ private static final String[] lastnames = new String[] { "Torvalds",
+ "Smith", "Adams", "Black", "Wilson", "Richards", "Thompson",
+ "McGoff", "Halas", "Jones", "Beck", "Sheridan", "Picard", "Hill",
+ "Fielding", "Einstein" };
+
+ public static IndexedContainer getPersonContainer() {
+ IndexedContainer contactContainer = new IndexedContainer();
+ contactContainer.addContainerProperty(PERSON_PROPERTY_FIRSTNAME,
+ String.class, "");
+ contactContainer.addContainerProperty(PERSON_PROPERTY_LASTNAME,
+ String.class, "");
+ for (int i = 0; i < 50;) {
+ String fn = firstnames[(int) (Math.random() * firstnames.length)];
+ String ln = lastnames[(int) (Math.random() * lastnames.length)];
+ String id = fn + ln;
+ Item item = contactContainer.addItem(id);
+ if (item != null) {
+ i++;
+ item.getItemProperty(PERSON_PROPERTY_FIRSTNAME).setValue(fn);
+ item.getItemProperty(PERSON_PROPERTY_LASTNAME).setValue(ln);
+ }
+ }
+ return contactContainer;
+ }
+
+ public static IndexedContainer getLocaleContainer() {
+ IndexedContainer localeContainer = new IndexedContainer();
+ localeContainer.addContainerProperty(locale_PROPERTY_LOCALE,
+ Locale.class, null);
+ localeContainer.addContainerProperty(locale_PROPERTY_NAME,
+ String.class, null);
+ for (int i = 0; i < locales.length; i++) {
+ String id = locales[i][2];
+ Item item = localeContainer.addItem(id);
+ item.getItemProperty(locale_PROPERTY_LOCALE).setValue(
+ new Locale(locales[i][0], locales[i][1]));
+ item.getItemProperty(locale_PROPERTY_NAME).setValue(locales[i][2]);
+ }
+
+ return localeContainer;
+ }
+
+ @Deprecated
+ public static IndexedContainer getStaticISO3166Container() {
+ return getISO3166Container();
+ }
+
+ public static IndexedContainer getISO3166Container() {
+ IndexedContainer c = new IndexedContainer();
+ fillIso3166Container(c);
+ return c;
+ }
+
+ private static void fillIso3166Container(IndexedContainer container) {
+ container.addContainerProperty(iso3166_PROPERTY_NAME, String.class,
+ null);
+ container.addContainerProperty(iso3166_PROPERTY_SHORT, String.class,
+ null);
+ container.addContainerProperty(iso3166_PROPERTY_FLAG, Resource.class,
+ null);
+ for (int i = 0; i < iso3166.length; i++) {
+ String name = iso3166[i++];
+ String id = iso3166[i];
+ Item item = container.addItem(id);
+ item.getItemProperty(iso3166_PROPERTY_NAME).setValue(name);
+ item.getItemProperty(iso3166_PROPERTY_SHORT).setValue(id);
+ item.getItemProperty(iso3166_PROPERTY_FLAG).setValue(
+ new ThemeResource("flags/" + id.toLowerCase() + ".gif"));
+ }
+ container.sort(new Object[] { iso3166_PROPERTY_NAME },
+ new boolean[] { true });
+ }
+
+ public static HierarchicalContainer getHardwareContainer() {
+ Item item = null;
+ int itemId = 0; // Increasing numbering for itemId:s
+
+ // Create new container
+ HierarchicalContainer hwContainer = new HierarchicalContainer();
+ // Create containerproperty for name
+ hwContainer.addContainerProperty(hw_PROPERTY_NAME, String.class, null);
+ for (int i = 0; i < hardware.length; i++) {
+ // Add new item
+ item = hwContainer.addItem(itemId);
+ // Add name property for item
+ item.getItemProperty(hw_PROPERTY_NAME).setValue(hardware[i][0]);
+ // Allow children
+ hwContainer.setChildrenAllowed(itemId, true);
+ itemId++;
+ for (int j = 1; j < hardware[i].length; j++) {
+ // Add child items
+ item = hwContainer.addItem(itemId);
+ item.getItemProperty(hw_PROPERTY_NAME).setValue(hardware[i][j]);
+ hwContainer.setParent(itemId, itemId - j);
+ hwContainer.setChildrenAllowed(itemId, false);
+ itemId++;
+ }
+ }
+ return hwContainer;
+ }
+
+ public static void fillContainerWithEmailAddresses(Container c, int amount) {
+ for (int i = 0; i < amount; i++) {
+ // TODO
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/Feature.java b/src/com/vaadin/demo/sampler/Feature.java
new file mode 100644
index 0000000000..e62951b340
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/Feature.java
@@ -0,0 +1,203 @@
+package com.vaadin.demo.sampler;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+
+import com.vaadin.ui.Component;
+
+/**
+ * Represents one feature or sample, with associated example.
+ * <p>
+ *
+ * </p>
+ *
+ */
+abstract public class Feature implements Serializable {
+
+ public static final Object PROPERTY_ICON = "Icon";
+ public static final Object PROPERTY_NAME = "Name";
+ public static final Object PROPERTY_DESCRIPTION = "Description";
+
+ private static final String MSG_SOURCE_NOT_AVAILABLE = "I'm terribly sorry,"
+ + " but it seems the source could not be found.\n"
+ + "Please try adding the source folder to the classpath for your"
+ + " server, or tell the administrator to do so!";
+
+ private static final Object MUTEX = new Object();
+ private String javaSource = null;
+
+ /**
+ * Gets the name of this feature. Try not to exceed 25 characters too much.
+ *
+ * @return
+ */
+ abstract public String getName();
+
+ /**
+ * Gets the description for this feature. Should describe what the example
+ * intends to showcase. May contain HTML. 100 words should be enough, and
+ * about 7 rows...
+ *
+ * @return the description
+ */
+ abstract public String getDescription();
+
+ /**
+ * Gets related resources, i.e links to resources related to the example.
+ * <p>
+ * Good candidates are resources used to make the example (CSS, images,
+ * custom layouts), documentation links (reference manual), articles (e.g.
+ * pattern description, usability discussion).
+ * </p>
+ * <p>
+ * May return null, if the example has no related resources.
+ * </p>
+ * <p>
+ * The name of the NamedExternalResource will be shown in the UI. <br/>
+ * Note that Javadoc should be referenced via {@link #getRelatedAPI()}.
+ * </p>
+ *
+ * @see #getThemeBase()
+ * @return related external stuff
+ */
+ abstract public NamedExternalResource[] getRelatedResources();
+
+ /**
+ * Gets related API resources, i.e links to javadoc of used classes.
+ * <p>
+ * Good candidates are IT Mill classes being demoed in the example, or other
+ * classes playing an important role in the example.
+ * </p>
+ * <p>
+ * May return null, if the example uses no interesting classes.
+ * <p>
+ *
+ * @return
+ */
+ abstract public APIResource[] getRelatedAPI();
+
+ /**
+ * Gets related Features; the classes returned should extend Feature.
+ * <p>
+ * Good candidates are Features similar to this one, Features using the
+ * functionality demoed in this one, and Features being used in this one.
+ * </p>
+ * <p>
+ * May return null, if no other Features are related to this one.
+ * <p>
+ *
+ * @return
+ */
+ abstract public Class[] getRelatedFeatures();
+
+ /**
+ * Gets the name of the icon for this feature, usually simpleName +
+ * extension.
+ *
+ * @return
+ */
+ public String getIconName() {
+ String icon = getClass().getSimpleName() + ".png";
+ return icon;
+ }
+
+ /**
+ * Get the example instance. Override if instantiation needs parameters.
+ *
+ * @return
+ */
+ public Component getExample() {
+
+ String className = this.getClass().getName() + "Example";
+ try {
+ Class<?> classObject = getClass().getClassLoader().loadClass(
+ className);
+ return (Component) classObject.newInstance();
+ } catch (ClassNotFoundException e) {
+ return null;
+ } catch (InstantiationException e) {
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+
+ }
+
+ public String getSource() {
+ synchronized (MUTEX) {
+ if (javaSource == null) {
+ StringBuffer src = new StringBuffer();
+ try {
+ /*
+ * Use package name + class name so the class loader won't
+ * have to guess the package name.
+ */
+ String resourceName = "/"
+ + getExample().getClass().getName().replace('.',
+ '/') + ".java";
+ InputStream is = getClass().getResourceAsStream(
+ resourceName);
+ BufferedReader bis = new BufferedReader(
+ new InputStreamReader(is));
+ for (String line = bis.readLine(); null != line; line = bis
+ .readLine()) {
+ src.append(line);
+ src.append("\n");
+ }
+ javaSource = src.toString();
+ } catch (Exception e) {
+ System.err.println(MSG_SOURCE_NOT_AVAILABLE + " ("
+ + getPathName() + ")");
+ javaSource = MSG_SOURCE_NOT_AVAILABLE;
+ }
+ }
+ }
+ return javaSource;
+
+ }
+
+ public String getSourceHTML() {
+ return getSource();
+ }
+
+ /**
+ * Gets the name used when resolving the path for this feature. Usually no
+ * need to override.
+ *
+ * @return
+ */
+ public String getPathName() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * Gets the base url used to reference theme resources.
+ *
+ * @return
+ */
+ protected static final String getThemeBase() {
+ return SamplerApplication.getThemeBase();
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // A feature is uniquely identified by its class name
+ if (obj == null) {
+ return false;
+ }
+ return obj.getClass() == getClass();
+ }
+
+ @Override
+ public int hashCode() {
+ // A feature is uniquely identified by its class name
+ return getClass().hashCode();
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/FeatureSet.java b/src/com/vaadin/demo/sampler/FeatureSet.java
new file mode 100644
index 0000000000..80a8e83206
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/FeatureSet.java
@@ -0,0 +1,543 @@
+package com.vaadin.demo.sampler;
+
+import java.util.Collections;
+import java.util.LinkedList;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.demo.sampler.features.accordions.AccordionDisabled;
+import com.vaadin.demo.sampler.features.accordions.AccordionIcons;
+import com.vaadin.demo.sampler.features.blueprints.ProminentPrimaryAction;
+import com.vaadin.demo.sampler.features.buttons.ButtonLink;
+import com.vaadin.demo.sampler.features.buttons.ButtonPush;
+import com.vaadin.demo.sampler.features.buttons.ButtonSwitch;
+import com.vaadin.demo.sampler.features.commons.Errors;
+import com.vaadin.demo.sampler.features.commons.Icons;
+import com.vaadin.demo.sampler.features.commons.Tooltips;
+import com.vaadin.demo.sampler.features.commons.Validation;
+import com.vaadin.demo.sampler.features.dates.DateInline;
+import com.vaadin.demo.sampler.features.dates.DateLocale;
+import com.vaadin.demo.sampler.features.dates.DatePopup;
+import com.vaadin.demo.sampler.features.dates.DateResolution;
+import com.vaadin.demo.sampler.features.form.FormBasic;
+import com.vaadin.demo.sampler.features.layouts.ApplicationLayout;
+import com.vaadin.demo.sampler.features.layouts.CustomLayouts;
+import com.vaadin.demo.sampler.features.layouts.ExpandingComponent;
+import com.vaadin.demo.sampler.features.layouts.GridLayoutBasic;
+import com.vaadin.demo.sampler.features.layouts.HorizontalLayoutBasic;
+import com.vaadin.demo.sampler.features.layouts.LayoutAlignment;
+import com.vaadin.demo.sampler.features.layouts.LayoutMargin;
+import com.vaadin.demo.sampler.features.layouts.LayoutSpacing;
+import com.vaadin.demo.sampler.features.layouts.SplitPanelBasic;
+import com.vaadin.demo.sampler.features.layouts.VerticalLayoutBasic;
+import com.vaadin.demo.sampler.features.layouts.WebLayout;
+import com.vaadin.demo.sampler.features.link.LinkCurrentWindow;
+import com.vaadin.demo.sampler.features.link.LinkNoDecorations;
+import com.vaadin.demo.sampler.features.link.LinkSizedWindow;
+import com.vaadin.demo.sampler.features.notifications.NotificationCustom;
+import com.vaadin.demo.sampler.features.notifications.NotificationError;
+import com.vaadin.demo.sampler.features.notifications.NotificationHumanized;
+import com.vaadin.demo.sampler.features.notifications.NotificationTray;
+import com.vaadin.demo.sampler.features.notifications.NotificationWarning;
+import com.vaadin.demo.sampler.features.panels.PanelBasic;
+import com.vaadin.demo.sampler.features.panels.PanelLight;
+import com.vaadin.demo.sampler.features.selects.ComboBoxContains;
+import com.vaadin.demo.sampler.features.selects.ComboBoxInputPrompt;
+import com.vaadin.demo.sampler.features.selects.ComboBoxNewItems;
+import com.vaadin.demo.sampler.features.selects.ComboBoxPlain;
+import com.vaadin.demo.sampler.features.selects.ComboBoxStartsWith;
+import com.vaadin.demo.sampler.features.selects.ListSelectMultiple;
+import com.vaadin.demo.sampler.features.selects.ListSelectSingle;
+import com.vaadin.demo.sampler.features.selects.NativeSelection;
+import com.vaadin.demo.sampler.features.selects.TwinColumnSelect;
+import com.vaadin.demo.sampler.features.table.TableActions;
+import com.vaadin.demo.sampler.features.table.TableCellStyling;
+import com.vaadin.demo.sampler.features.table.TableColumnAlignment;
+import com.vaadin.demo.sampler.features.table.TableColumnCollapsing;
+import com.vaadin.demo.sampler.features.table.TableColumnHeaders;
+import com.vaadin.demo.sampler.features.table.TableColumnReordering;
+import com.vaadin.demo.sampler.features.table.TableHeaderIcons;
+import com.vaadin.demo.sampler.features.table.TableLazyLoading;
+import com.vaadin.demo.sampler.features.table.TableMouseEvents;
+import com.vaadin.demo.sampler.features.table.TableRowHeaders;
+import com.vaadin.demo.sampler.features.table.TableRowStyling;
+import com.vaadin.demo.sampler.features.table.TableSorting;
+import com.vaadin.demo.sampler.features.tabsheets.TabSheetDisabled;
+import com.vaadin.demo.sampler.features.tabsheets.TabSheetIcons;
+import com.vaadin.demo.sampler.features.tabsheets.TabSheetScrolling;
+import com.vaadin.demo.sampler.features.text.LabelPlain;
+import com.vaadin.demo.sampler.features.text.LabelPreformatted;
+import com.vaadin.demo.sampler.features.text.LabelRich;
+import com.vaadin.demo.sampler.features.text.RichTextEditor;
+import com.vaadin.demo.sampler.features.text.TextArea;
+import com.vaadin.demo.sampler.features.text.TextFieldInputPrompt;
+import com.vaadin.demo.sampler.features.text.TextFieldSecret;
+import com.vaadin.demo.sampler.features.text.TextFieldSingle;
+import com.vaadin.demo.sampler.features.trees.TreeActions;
+import com.vaadin.demo.sampler.features.trees.TreeMouseEvents;
+import com.vaadin.demo.sampler.features.trees.TreeMultiSelect;
+import com.vaadin.demo.sampler.features.trees.TreeSingleSelect;
+import com.vaadin.demo.sampler.features.windows.NativeWindow;
+import com.vaadin.demo.sampler.features.windows.Subwindow;
+import com.vaadin.demo.sampler.features.windows.SubwindowAutoSized;
+import com.vaadin.demo.sampler.features.windows.SubwindowClose;
+import com.vaadin.demo.sampler.features.windows.SubwindowModal;
+import com.vaadin.demo.sampler.features.windows.SubwindowPositioned;
+import com.vaadin.demo.sampler.features.windows.SubwindowSized;
+
+/**
+ * Contains the FeatureSet implementation and the structure for the feature
+ * 'tree'.
+ * <p>
+ * Each set is implemented as it's own class to facilitate linking to sets in
+ * the same way as linking to individual features.
+ * </p>
+ *
+ */
+public class FeatureSet extends Feature {
+
+ /*
+ * MAIN structure; root is always a FeatureSet that is not shown
+ */
+ static final FeatureSet FEATURES = new FeatureSet("All", new Feature[] {
+ // Main sets
+ // new Blueprints(), disabled for now, until more samples are ready
+ new Components(), //
+ });
+
+ /*
+ * TOP LEVEL
+ */
+ public static class Blueprints extends FeatureSet {
+ public Blueprints() {
+ super("Blueprints", new Feature[] {
+ // Blueprints
+ new ProminentPrimaryAction(), //
+ });
+ }
+ }
+
+ public static class Components extends FeatureSet {
+ public Components() {
+ super("Components", new Feature[] {
+ //
+ new Common(), //
+ new Accordions(), //
+ new Buttons(), //
+ new Dates(), //
+ new Forms(), //
+ new Layouts(), //
+ new Links(), //
+ new Notifications(), //
+ new Panels(), //
+ new Selects(), //
+ new Tables(),//
+ new Tabsheets(), //
+ new Texts(), //
+ new TextFields(), //
+ new Trees(), //
+ new Windows(), //
+ });
+ }
+ }
+
+ /*
+ * LEVEL 2
+ */
+ public static class Buttons extends FeatureSet {
+ public Buttons() {
+ super(
+ "Buttons",
+ "Buttons",
+ "A button is one of the fundamental building blocks of any application.",
+ new Feature[] {
+ //
+ new ButtonPush(), // basic
+ new ButtonLink(), // link
+ new ButtonSwitch(), // switch/checkbox
+
+ });
+ }
+ }
+
+ public static class Links extends FeatureSet {
+ public Links() {
+ super(
+ "Links",
+ "Links",
+ "An external link. This is the basic HTML-style link, changing the url of the browser w/o triggering a server-side event (like the link-styled Button).",
+ new Feature[] {
+ //
+ new LinkCurrentWindow(), // basic
+ new LinkNoDecorations(), // new win
+ new LinkSizedWindow(), // new win
+
+ });
+ }
+ }
+
+ public static class Notifications extends FeatureSet {
+ public Notifications() {
+ super(
+ "Notifications",
+ "Notifications",
+ "Notifications are lightweight informational messages, used to inform the user of various events.",
+ new Feature[] {
+ //
+ new NotificationHumanized(), // humanized
+ new NotificationWarning(), // warning
+ new NotificationTray(), // tray
+ new NotificationError(), // error
+ new NotificationCustom(), // error
+ });
+ }
+ }
+
+ public static class Common extends FeatureSet {
+ public Common() {
+ super("Common", new Feature[] {
+ //
+ new Tooltips(), //
+ new Icons(), //
+ new Errors(), //
+ new Validation(), // TODO this should point to Form instead
+ });
+ }
+ }
+
+ public static class Selects extends FeatureSet {
+ public Selects() {
+ super("Selects", new Feature[] {
+ //
+ new ListSelectSingle(), //
+ new ListSelectMultiple(), //
+ new TwinColumnSelect(), //
+ new NativeSelection(), //
+ new ComboBoxPlain(), //
+ new ComboBoxInputPrompt(), //
+ new ComboBoxStartsWith(), //
+ new ComboBoxContains(), //
+ new ComboBoxNewItems(), //
+
+ });
+ }
+ }
+
+ public static class Layouts extends FeatureSet {
+ public Layouts() {
+ super(
+ "Layouts",
+ "Layouts",
+ "Making a usable, good looking, dynamic layout can be tricky, but with the right tools almost anything is possible.<br/>",
+ new Feature[] {
+ //
+ new LayoutMargin(), //
+ new LayoutSpacing(), //
+ new VerticalLayoutBasic(), //
+ new HorizontalLayoutBasic(), //
+ new GridLayoutBasic(), //
+ new LayoutAlignment(), //
+ new ExpandingComponent(), //
+ new SplitPanelBasic(), //
+ new ApplicationLayout(), //
+ new WebLayout(), //
+ new CustomLayouts(), //
+ });
+ }
+ }
+
+ public static class Tabsheets extends FeatureSet {
+ public Tabsheets() {
+ super(
+ "Tabsheets",
+ "Tabsheets",
+ "A Tabsheet organizes multiple components so that only the one component associated with the currently selected 'tab' is shown. Typically a tab will contain a Layout, which in turn may contain many components.",
+ new Feature[] {
+ //
+ new TabSheetIcons(), //
+ new TabSheetScrolling(), //
+ new TabSheetDisabled(), //
+ });
+ }
+ }
+
+ public static class Accordions extends FeatureSet {
+ public Accordions() {
+ super(
+ "Accordions",
+ "Accordions",
+ "An accordion component is a specialized case of a tabsheet."
+ + " Within an accordion, the tabs are organized vertically,"
+ + " and the content will be shown directly below the tab.",
+ new Feature[] {
+ //
+ new AccordionIcons(), //
+ new AccordionDisabled(), //
+ });
+ }
+ }
+
+ public static class Panels extends FeatureSet {
+ public Panels() {
+ super(
+ "Panels",
+ "Panels",
+ "Panel is a simple container that supports scrolling.<br/>It's internal layout (by default VerticalLayout) can be configured or exchanged to get desired results. Components that are added to the Panel will in effect be added to the layout.",
+ new Feature[] {
+ //
+ new PanelBasic(), //
+ new PanelLight(), //
+ });
+ }
+ }
+
+ public static class Forms extends FeatureSet {
+ public Forms() {
+ super("Forms", "Forms",
+ "The Form -component provides a convenient way to organize"
+ + " related fields visually.", new Feature[] {
+ //
+ new FormBasic(), //
+ });
+ }
+ }
+
+ public static class Windows extends FeatureSet {
+ public Windows() {
+ super(
+ "Windows",
+ "Windows",
+ "Windows can (for instance) organize the UI, save space (popup windows), focus attention (modal windows), or provide multiple views for the same data for multitasking or dual screen setups (native browser windows).",
+ new Feature[] {
+ //
+ new Subwindow(), //
+ new SubwindowModal(), //
+ new SubwindowAutoSized(), //
+ new SubwindowSized(), //
+ new SubwindowPositioned(), //
+ new SubwindowClose(), //
+ new NativeWindow(), //
+ });
+ }
+ }
+
+ public static class Tables extends FeatureSet {
+ public Tables() {
+ super(
+ "Table (Grid)",
+ "Table (Grid)",
+ "A Table, also known as a (Data)Grid, can be used to show data in a tabular fashion. It's well suited for showing large datasets.",
+ new Feature[] {
+ //
+ new TableHeaderIcons(), //
+ new TableColumnHeaders(), //
+ new TableColumnReordering(), //
+ new TableColumnCollapsing(), //
+ new TableColumnAlignment(), //
+ new TableCellStyling(), //
+ new TableSorting(), //
+ new TableRowHeaders(), //
+ new TableRowStyling(), //
+ new TableActions(), //
+ new TableMouseEvents(), //
+ new TableLazyLoading(), //
+ });
+ }
+ }
+
+ public static class Texts extends FeatureSet {
+ public Texts() {
+ super(
+ "Texts",
+ "Texts",
+ "A label is a simple component that allows you to add (optionally formatted) text components to your application.",
+ new Feature[] {
+ //
+ new LabelPlain(), //
+ new LabelPreformatted(), //
+ new LabelRich(), //
+ });
+ }
+ }
+
+ public static class TextFields extends FeatureSet {
+ public TextFields() {
+ super(
+ "TextFields",
+ "Text inputs",
+ "Text inputs are probably the most needed components in any application that require user input or editing.",
+ new Feature[] {
+ //
+ new TextFieldSingle(), //
+ new TextFieldSecret(), //
+ new TextFieldInputPrompt(), //
+ new TextArea(), //
+ new RichTextEditor(), //
+ });
+ }
+ }
+
+ public static class Trees extends FeatureSet {
+ public Trees() {
+ super(
+ "Trees",
+ "Trees",
+ "The Tree component provides a natural way to represent data that has hierarchical relationships, such as filesystems or message threads.",
+ new Feature[] {
+ //
+ new TreeSingleSelect(), //
+ new TreeMultiSelect(), //
+ new TreeActions(), //
+ new TreeMouseEvents(), //
+ });
+ }
+ }
+
+ public static class Dates extends FeatureSet {
+ public Dates() {
+ super(
+ "Dates",
+ "Dates",
+ "The DateField component can be used to produce various date and time input fields with different resolutions. The date and time format used with this component is reported to the Toolkit by the browser.",
+ new Feature[] {
+ //
+ new DatePopup(), //
+ new DateInline(), //
+ new DateLocale(), //
+ new DateResolution(), //
+ });
+ }
+ }
+
+ // ----------------------------------------------------------
+ /*
+ * FeatureSet implementation follows.
+ */
+
+ private String pathname;
+
+ private String name;
+
+ private String desc;
+
+ private String icon = "folder.gif";
+
+ private Feature[] content;
+
+ private HierarchicalContainer container = null;
+
+ private boolean containerRecursive = false;
+
+ FeatureSet(String pathname, Feature[] content) {
+ this(pathname, pathname, "", content);
+ }
+
+ FeatureSet(String pathname, String name, Feature[] content) {
+ this(pathname, name, "", content);
+ }
+
+ FeatureSet(String pathname, String name, String desc, Feature[] content) {
+ this.pathname = pathname;
+ this.name = name;
+ this.desc = desc;
+ this.content = content;
+ }
+
+ Feature[] getFeatures() {
+ return content;
+ }
+
+ Feature getFeatureByPath(String path) {
+ LinkedList<String> parts = new LinkedList<String>();
+ Collections.addAll(parts, path.split("/"));
+ FeatureSet f = this;
+ while (f != null) {
+ Feature[] fs = f.getFeatures();
+ f = null; // break while if no new found
+ String part = parts.remove(0);
+ for (int i = 0; i < fs.length; i++) {
+ if (fs[i].getPathName().equalsIgnoreCase(part)) {
+ if (parts.isEmpty()) {
+ return fs[i];
+ } else if (fs[i] instanceof FeatureSet) {
+ f = (FeatureSet) fs[i];
+ break;
+ } else {
+ return null;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ HierarchicalContainer getContainer(boolean recurse) {
+ if (container == null || containerRecursive != recurse) {
+ container = new HierarchicalContainer();
+ container.addContainerProperty(PROPERTY_NAME, String.class, "");
+ container.addContainerProperty(PROPERTY_DESCRIPTION, String.class,
+ "");
+ // fill
+ addFeatures(this, container, recurse);
+ }
+ return container;
+ }
+
+ private void addFeatures(FeatureSet f, HierarchicalContainer c,
+ boolean recurse) {
+ Feature[] features = f.getFeatures();
+ for (int i = 0; i < features.length; i++) {
+ Item item = c.addItem(features[i]);
+ Property property = item.getItemProperty(PROPERTY_NAME);
+ property.setValue(features[i].getName());
+ property = item.getItemProperty(PROPERTY_DESCRIPTION);
+ property.setValue(features[i].getDescription());
+ if (recurse) {
+ c.setParent(features[i], f);
+ if (features[i] instanceof FeatureSet) {
+ addFeatures((FeatureSet) features[i], c, recurse);
+ }
+ }
+ if (!(features[i] instanceof FeatureSet)) {
+ c.setChildrenAllowed(features[i], false);
+ }
+ }
+ }
+
+ @Override
+ public String getDescription() {
+ return desc;
+ }
+
+ @Override
+ public String getPathName() {
+ return pathname;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getIconName() {
+ return icon;
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return null;
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return null;
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/FeatureView.java b/src/com/vaadin/demo/sampler/FeatureView.java
new file mode 100644
index 0000000000..02ff91117b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/FeatureView.java
@@ -0,0 +1,258 @@
+package com.vaadin.demo.sampler;
+
+import java.util.HashMap;
+
+import com.vaadin.demo.sampler.ActiveLink.LinkActivatedEvent;
+import com.vaadin.demo.sampler.ActiveLink.LinkActivatedListener;
+import com.vaadin.demo.sampler.SamplerApplication.SamplerWindow;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class FeatureView extends HorizontalLayout {
+
+ private static final String MSG_SHOW_SRC = "Show Java™ source »";
+
+ private Panel right;
+ private VerticalLayout left;
+
+ private VerticalLayout controls;
+
+ private ActiveLink showSrc;
+
+ private HashMap<Feature, Component> exampleCache = new HashMap<Feature, Component>();
+
+ private Feature currentFeature;
+
+ private Window srcWindow;
+
+ public FeatureView() {
+
+ setWidth("100%");
+ setMargin(true);
+ setSpacing(true);
+ setStyleName("sample-view");
+
+ left = new VerticalLayout();
+ left.setWidth("100%");
+ left.setSpacing(true);
+ left.setMargin(false);
+ addComponent(left);
+ setExpandRatio(left, 1);
+
+ right = new Panel();
+ right.getLayout().setMargin(true, false, false, false);
+ right.setStyleName(Panel.STYLE_LIGHT);
+ right.addStyleName("feature-info");
+ right.setWidth("369px");
+ addComponent(right);
+
+ controls = new VerticalLayout();
+ controls.setWidth("100%");
+ controls.setStyleName("feature-controls");
+
+ HorizontalLayout controlButtons = new HorizontalLayout();
+ controls.addComponent(controlButtons);
+
+ Button resetExample = new Button("Reset example",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ resetExample();
+ }
+ });
+ resetExample.setStyleName(Button.STYLE_LINK);
+ resetExample.addStyleName("showcode");
+ controlButtons.addComponent(resetExample);
+
+ controlButtons.addComponent(new Label("|"));
+
+ showSrc = new ActiveLink();
+ showSrc
+ .setDescription("Right / middle / ctrl / shift -click for browser window/tab");
+ showSrc.addListener(new LinkActivatedListener() {
+
+ public void linkActivated(LinkActivatedEvent event) {
+ if (!event.isLinkOpened()) {
+ showSource(currentFeature.getSource());
+ }
+
+ }
+
+ });
+ showSrc.setCaption(MSG_SHOW_SRC);
+ showSrc.addStyleName("showcode");
+ showSrc.setTargetBorder(Link.TARGET_BORDER_NONE);
+ controlButtons.addComponent(showSrc);
+
+ }
+
+ public void showSource(String source) {
+ if (srcWindow == null) {
+ srcWindow = new Window("Javaâ„¢ source");
+ ((VerticalLayout) srcWindow.getLayout()).setSizeUndefined();
+ srcWindow.setWidth("70%");
+ srcWindow.setHeight("60%");
+ srcWindow.setPositionX(100);
+ srcWindow.setPositionY(100);
+ }
+ srcWindow.removeAllComponents();
+ srcWindow.addComponent(new CodeLabel(source));
+
+ if (srcWindow.getParent() == null) {
+ getWindow().addWindow(srcWindow);
+ }
+ }
+
+ private void resetExample() {
+ if (currentFeature != null) {
+ Feature f = currentFeature;
+ currentFeature = null;
+ exampleCache.remove(f);
+ setFeature(f);
+ }
+ }
+
+ public void setFeature(Feature feature) {
+ if (feature != currentFeature) {
+ currentFeature = feature;
+ right.removeAllComponents();
+ left.removeAllComponents();
+
+ left.addComponent(controls);
+ controls.setCaption(feature.getName());
+
+ left.addComponent(getExampleFor(feature));
+
+ right.setCaption("Description and Resources");
+
+ final Feature parent = (Feature) SamplerApplication
+ .getAllFeatures().getParent(feature);
+ String desc = parent.getDescription();
+ boolean hasParentDesc = false;
+
+ final Label parentLabel = new Label(parent.getDescription());
+ if (desc != null && desc != "") {
+ parentLabel.setContentMode(Label.CONTENT_XHTML);
+ right.addComponent(parentLabel);
+ hasParentDesc = true;
+ }
+
+ desc = feature.getDescription();
+ if (desc != null && desc != "") {
+ // Sample description uses additional decorations if a parent
+ // description is found
+ final Label l = new Label(
+ "<div class=\"outer-deco\"><div class=\"deco\"><span class=\"deco\"></span>"
+ + desc + "</div></div>", Label.CONTENT_XHTML);
+ right.addComponent(l);
+ if (hasParentDesc) {
+ l.setStyleName("sample-description");
+ } else {
+ l.setStyleName("description");
+ }
+ }
+
+ { // open src in new window -link
+ String path = SamplerApplication.getPathFor(currentFeature);
+ showSrc.setTargetName(path);
+ showSrc.setResource(new ExternalResource(getApplication()
+ .getURL()
+ + "src/" + path));
+ }
+
+ NamedExternalResource[] resources = feature.getRelatedResources();
+ if (resources != null) {
+ VerticalLayout res = new VerticalLayout();
+ Label caption = new Label("<span>Additional Resources</span>",
+ Label.CONTENT_XHTML);
+ caption.setStyleName("section");
+ caption.setWidth("100%");
+ res.addComponent(caption);
+ res.setMargin(false, false, true, false);
+ for (NamedExternalResource r : resources) {
+ final Link l = new Link(r.getName(), r);
+ l
+ .setIcon(new ThemeResource(
+ "../default/icons/16/note.png"));
+ res.addComponent(l);
+ }
+ right.addComponent(res);
+ }
+
+ APIResource[] apis = feature.getRelatedAPI();
+ if (apis != null) {
+ VerticalLayout api = new VerticalLayout();
+ Label caption = new Label("<span>API Documentation</span>",
+ Label.CONTENT_XHTML);
+ caption.setStyleName("section");
+ caption.setWidth("100%");
+ api.addComponent(caption);
+ api.setMargin(false, false, true, false);
+ for (APIResource r : apis) {
+ final Link l = new Link(r.getName(), r);
+ l.setIcon(new ThemeResource(
+ "../default/icons/16/document-txt.png"));
+ api.addComponent(l);
+ }
+ right.addComponent(api);
+ }
+
+ Class[] features = feature.getRelatedFeatures();
+ if (features != null) {
+ VerticalLayout rel = new VerticalLayout();
+ Label caption = new Label("<span>Related Samples</span>",
+ Label.CONTENT_XHTML);
+ caption.setStyleName("section");
+ caption.setWidth("100%");
+ rel.addComponent(caption);
+ rel.setMargin(false, false, true, false);
+ for (Class c : features) {
+ final Feature f = SamplerApplication.getFeatureFor(c);
+ if (f != null) {
+ String path = SamplerApplication.getPathFor(f);
+ ActiveLink al = new ActiveLink(f.getName(),
+ new ExternalResource(getApplication().getURL()
+ + "#" + path));
+ al.setIcon(new ThemeResource(
+ (f instanceof FeatureSet ? "icons/category.gif"
+ : "icons/sample.png")));
+ al.addListener(new LinkActivatedListener() {
+ public void linkActivated(LinkActivatedEvent event) {
+ if (event.isLinkOpened()) {
+ getWindow()
+ .showNotification(
+ f.getName()
+ + " opened if new window/tab");
+ } else {
+ SamplerWindow w = (SamplerWindow) getWindow();
+ w.setFeature(f);
+ }
+ }
+ });
+ rel.addComponent(al);
+ }
+ }
+ right.addComponent(rel);
+ }
+ }
+
+ }
+
+ private Component getExampleFor(Feature f) {
+ Component ex = exampleCache.get(f);
+ if (ex == null) {
+ ex = f.getExample();
+ exampleCache.put(f, ex);
+ }
+ return ex;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/GoogleAnalytics.java b/src/com/vaadin/demo/sampler/GoogleAnalytics.java
new file mode 100644
index 0000000000..345844cee6
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/GoogleAnalytics.java
@@ -0,0 +1,54 @@
+package com.vaadin.demo.sampler;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.AbstractComponent;
+
+public class GoogleAnalytics extends AbstractComponent {
+
+ private String trackerId;
+ private String pageId;
+ private String domainName;
+
+ private static final String TAG = "googleanalytics";
+
+ public GoogleAnalytics(String trackerId) {
+ this.trackerId = trackerId;
+ }
+
+ public GoogleAnalytics(String trackerId, String domainName) {
+ this(trackerId);
+ this.domainName = domainName;
+ }
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
+ public String getTrackerId() {
+ return trackerId;
+ }
+
+ public String getDomainName() {
+ return domainName;
+ }
+
+ public void trackPageview(String pageId) {
+ this.pageId = pageId;
+ requestRepaint();
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+ target.addAttribute("trackerid", trackerId);
+ if (pageId != null) {
+ target.addAttribute("pageid", pageId);
+ }
+ if (domainName != null) {
+ target.addAttribute("domain", domainName);
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/ModeSwitch.java b/src/com/vaadin/demo/sampler/ModeSwitch.java
new file mode 100644
index 0000000000..c6565c0c61
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/ModeSwitch.java
@@ -0,0 +1,106 @@
+package com.vaadin.demo.sampler;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.vaadin.terminal.Resource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+@SuppressWarnings("serial")
+public class ModeSwitch extends CustomComponent {
+
+ GridLayout layout = new GridLayout(3, 1);
+
+ HashMap<Object, Button> idToButton = new HashMap<Object, Button>();
+ Object mode = null;
+
+ public ModeSwitch() {
+ setSizeUndefined();
+ layout.setSizeUndefined();
+ setCompositionRoot(layout);
+ setStyleName("ModeSwitch");
+ }
+
+ public Object getMode() {
+ return mode;
+ }
+
+ public void setMode(Object mode) {
+ if (idToButton.containsKey(mode)) {
+ this.mode = mode;
+ updateStyles();
+ fireEvent(new ModeSwitchEvent());
+ }
+ }
+
+ public void addListener(ModeSwitchListener listener) {
+ super.addListener(listener);
+ }
+
+ public void addMode(Object id, String caption, String description,
+ Resource icon) {
+ if (idToButton.containsKey(id)) {
+ removeMode(id);
+ }
+ Button b = new Button();
+ if (caption != null) {
+ b.setCaption(caption);
+ }
+ if (description != null) {
+ b.setDescription(description);
+ }
+ if (icon != null) {
+ b.setIcon(icon);
+ }
+ b.setData(id);
+ b.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ setMode(event.getButton().getData());
+ }
+ });
+ idToButton.put(id, b);
+ layout.addComponent(b);
+ updateStyles();
+ }
+
+ public void removeMode(Object id) {
+ Button b = idToButton.remove(id);
+ layout.removeComponent(b);
+ updateStyles();
+ }
+
+ private void updateStyles() {
+ boolean first = true;
+ for (Iterator it = layout.getComponentIterator(); it.hasNext();) {
+ Button b = (Button) it.next();
+ String isOn = (b.getData() == mode ? "-on" : "");
+ if (first) {
+ first = false;
+ b.setStyleName("first" + isOn);
+ } else if (!it.hasNext()) {
+ b.setStyleName("last" + isOn);
+ } else {
+ b.setStyleName("mid" + isOn);
+ }
+ }
+ }
+
+ public interface ModeSwitchListener extends Listener {
+
+ }
+
+ public class ModeSwitchEvent extends Event {
+
+ public ModeSwitchEvent() {
+ super(ModeSwitch.this);
+ }
+
+ public Object getMode() {
+ return ModeSwitch.this.getMode();
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/NamedExternalResource.java b/src/com/vaadin/demo/sampler/NamedExternalResource.java
new file mode 100644
index 0000000000..16573f2ebb
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/NamedExternalResource.java
@@ -0,0 +1,18 @@
+package com.vaadin.demo.sampler;
+
+import com.vaadin.terminal.ExternalResource;
+
+public class NamedExternalResource extends ExternalResource {
+
+ private String name;
+
+ public NamedExternalResource(String name, String sourceURL) {
+ super(sourceURL);
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/SamplerApplication.java b/src/com/vaadin/demo/sampler/SamplerApplication.java
new file mode 100644
index 0000000000..bab73cd6a9
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/SamplerApplication.java
@@ -0,0 +1,777 @@
+package com.vaadin.demo.sampler;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.vaadin.Application;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.data.util.ObjectProperty;
+import com.vaadin.demo.sampler.ActiveLink.LinkActivatedEvent;
+import com.vaadin.demo.sampler.ModeSwitch.ModeSwitchEvent;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.terminal.ClassResource;
+import com.vaadin.terminal.DownloadStream;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.terminal.URIHandler;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.PopupView;
+import com.vaadin.ui.SplitPanel;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.UriFragmentUtility;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.PopupView.PopupVisibilityEvent;
+import com.vaadin.ui.UriFragmentUtility.FragmentChangedEvent;
+import com.vaadin.ui.UriFragmentUtility.FragmentChangedListener;
+
+@SuppressWarnings("serial")
+public class SamplerApplication extends Application {
+
+ // All features in one container
+ private static final HierarchicalContainer allFeatures = FeatureSet.FEATURES
+ .getContainer(true);
+
+ // init() inits
+ private static final String THEME_NAME = "sampler";
+
+ // used when trying to guess theme location
+ private static String APP_URL = null;
+
+ @Override
+ public void init() {
+ setTheme("sampler");
+ setMainWindow(new SamplerWindow());
+ APP_URL = getURL().toString();
+ }
+
+ /**
+ * Tries to guess theme location.
+ *
+ * @return
+ */
+ public static String getThemeBase() {
+ try {
+ URI uri = new URI(APP_URL + "../ITMILL/themes/" + THEME_NAME + "/");
+ return uri.normalize().toString();
+ } catch (Exception e) {
+ System.err.println("Theme location could not be resolved:" + e);
+ }
+ return "/ITMILL/themes/" + THEME_NAME + "/";
+ }
+
+ // Supports multiple browser windows
+ @Override
+ public Window getWindow(String name) {
+ Window w = super.getWindow(name);
+ if (w == null) {
+ if (name.startsWith("src")) {
+ w = new SourceWindow();
+ } else {
+ w = new SamplerWindow();
+ w.setName(name);
+ }
+
+ addWindow(w);
+ }
+ return w;
+
+ }
+
+ /**
+ * Gets absolute path for given Feature
+ *
+ * @param f
+ * the Feature whose path to get, of null if not found
+ * @return the path of the Feature
+ */
+ public static String getPathFor(Feature f) {
+ if (f == null) {
+ return "";
+ }
+ if (allFeatures.containsId(f)) {
+ String path = f.getPathName();
+ f = (Feature) allFeatures.getParent(f);
+ while (f != null) {
+ path = f.getPathName() + "/" + path;
+ f = (Feature) allFeatures.getParent(f);
+ }
+ return path;
+ }
+ return "";
+ }
+
+ /**
+ * Gets the instance for the given Feature class, e.g DummyFeature.class.
+ *
+ * @param clazz
+ * @return
+ */
+ public static Feature getFeatureFor(Class clazz) {
+ for (Iterator it = allFeatures.getItemIds().iterator(); it.hasNext();) {
+ Feature f = (Feature) it.next();
+ if (f.getClass() == clazz) {
+ return f;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * The main window for Sampler, contains the full application UI.
+ *
+ */
+ class SamplerWindow extends Window {
+ private FeatureList currentList = new FeatureGrid();
+ private FeatureView featureView = new FeatureView();
+ private ObjectProperty currentFeature = new ObjectProperty(null,
+ Feature.class);
+
+ private ModeSwitch mode;
+
+ private SplitPanel mainSplit;
+ private Tree navigationTree;
+ // itmill: UA-658457-6
+ private GoogleAnalytics webAnalytics = new GoogleAnalytics(
+ "UA-658457-6", "none");
+ // "backbutton"
+ UriFragmentUtility uriFragmentUtility = new UriFragmentUtility();
+
+ // breadcrumbs
+ BreadCrumbs breadcrumbs = new BreadCrumbs();
+
+ Button previousSample;
+ Button nextSample;
+ private ComboBox search;
+
+ @Override
+ public void detach() {
+ super.detach();
+
+ search.setContainerDataSource(null);
+ navigationTree.setContainerDataSource(null);
+ }
+
+ SamplerWindow() {
+ // Main top/expanded-bottom layout
+ VerticalLayout mainExpand = new VerticalLayout();
+ setLayout(mainExpand);
+ setSizeFull();
+ mainExpand.setSizeFull();
+
+ // topbar (navigation)
+ HorizontalLayout nav = new HorizontalLayout();
+ mainExpand.addComponent(nav);
+ nav.setHeight("44px");
+ nav.setWidth("100%");
+ nav.setStyleName("topbar");
+ nav.setSpacing(true);
+ nav.setMargin(false, true, false, false);
+
+ // Upper left logo
+ Component logo = createLogo();
+ nav.addComponent(logo);
+ nav.setComponentAlignment(logo, Alignment.MIDDLE_LEFT);
+
+ // Breadcrumbs
+ nav.addComponent(breadcrumbs);
+ nav.setExpandRatio(breadcrumbs, 1);
+ nav.setComponentAlignment(breadcrumbs, Alignment.MIDDLE_LEFT);
+
+ // invisible analytics -component
+ nav.addComponent(webAnalytics);
+
+ // "backbutton"
+ nav.addComponent(uriFragmentUtility);
+ uriFragmentUtility.addListener(new FragmentChangedListener() {
+ public void fragmentChanged(FragmentChangedEvent source) {
+ String frag = source.getUriFragmentUtility().getFragment();
+ setFeature(frag);
+ }
+ });
+
+ // Main left/right split; hidden menu tree
+ mainSplit = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL);
+ mainSplit.setSizeFull();
+ mainSplit.setStyleName("main-split");
+ mainExpand.addComponent(mainSplit);
+ mainExpand.setExpandRatio(mainSplit, 1);
+
+ // List/grid/coverflow
+ mode = createModeSwitch();
+ mode.setMode(currentList);
+ nav.addComponent(mode);
+ nav.setComponentAlignment(mode, Alignment.MIDDLE_LEFT);
+
+ // Layouts for top area buttons
+ HorizontalLayout quicknav = new HorizontalLayout();
+ HorizontalLayout arrows = new HorizontalLayout();
+ nav.addComponent(quicknav);
+ nav.addComponent(arrows);
+ nav.setComponentAlignment(quicknav, Alignment.MIDDLE_LEFT);
+ nav.setComponentAlignment(arrows, Alignment.MIDDLE_LEFT);
+ quicknav.setStyleName("segment");
+ arrows.setStyleName("segment");
+
+ // Previous sample
+ previousSample = createPrevButton();
+ arrows.addComponent(previousSample);
+ // Next sample
+ nextSample = createNextButton();
+ arrows.addComponent(nextSample);
+ // "Search" combobox
+ // TODO add input prompt
+ Component searchComponent = createSearch();
+ quicknav.addComponent(searchComponent);
+
+ // Menu tree, initially hidden
+ navigationTree = createMenuTree();
+ mainSplit.setFirstComponent(navigationTree);
+
+ // Show / hide tree
+ Component treeSwitch = createTreeSwitch();
+ quicknav.addComponent(treeSwitch);
+
+ addListener(new CloseListener() {
+ public void windowClose(CloseEvent e) {
+ if (getMainWindow() != SamplerWindow.this) {
+ SamplerApplication.this
+ .removeWindow(SamplerWindow.this);
+ }
+ }
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ public void removeSubwindows() {
+ Collection<Window> wins = getChildWindows();
+ if (null != wins) {
+ for (Window w : wins) {
+ removeWindow(w);
+ }
+ }
+ }
+
+ /**
+ * Displays a Feature(Set)
+ *
+ * @param f
+ * the Feature(Set) to show
+ */
+ public void setFeature(Feature f) {
+ removeSubwindows();
+ currentFeature.setValue(f);
+ String path = getPathFor(f);
+ webAnalytics.trackPageview(path);
+ uriFragmentUtility.setFragment(path, false);
+ breadcrumbs.setPath(path);
+
+ previousSample.setEnabled(f != null);
+ nextSample.setEnabled(!allFeatures.isLastId(f));
+
+ updateFeatureList(currentList);
+ }
+
+ /**
+ * Displays a Feature(Set) matching the given path, or the main view if
+ * no matching Feature(Set) is found.
+ *
+ * @param path
+ * the path of the Feature(Set) to show
+ */
+ public void setFeature(String path) {
+ Feature f = FeatureSet.FEATURES.getFeatureByPath(path);
+ setFeature(f);
+ }
+
+ /*
+ * SamplerWindow helpers
+ */
+
+ private Component createSearch() {
+ search = new ComboBox();
+ search.setWidth("160px");
+ search.setNewItemsAllowed(false);
+ search.setFilteringMode(ComboBox.FILTERINGMODE_CONTAINS);
+ search.setNullSelectionAllowed(true);
+ search.setImmediate(true);
+ search.setContainerDataSource(allFeatures);
+ for (Iterator it = allFeatures.getItemIds().iterator(); it
+ .hasNext();) {
+ Object id = it.next();
+ if (id instanceof FeatureSet) {
+ search.setItemIcon(id, new ClassResource("folder.gif",
+ SamplerApplication.this));
+ }
+ }
+ search.addListener(new ComboBox.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ Feature f = (Feature) event.getProperty().getValue();
+ if (f != null) {
+ SamplerWindow.this.setFeature(f);
+ event.getProperty().setValue(null);
+ }
+
+ }
+ });
+ // TODO add icons for section/sample
+ /*
+ * PopupView pv = new PopupView("", search) { public void
+ * changeVariables(Object source, Map variables) {
+ * super.changeVariables(source, variables); if (isPopupVisible()) {
+ * search.focus(); } } };
+ */
+ PopupView pv = new PopupView("<span></span>", search);
+ pv.addListener(new PopupView.PopupVisibilityListener() {
+ public void popupVisibilityChange(PopupVisibilityEvent event) {
+ if (event.isPopupVisible()) {
+ search.focus();
+ }
+ }
+ });
+ pv.setStyleName("quickjump");
+ pv.setDescription("Quick jump");
+
+ return pv;
+ }
+
+ private Component createLogo() {
+ Button logo = new Button("", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ setFeature((Feature) null);
+ }
+ });
+ logo.setDescription("↶ Home");
+ logo.setStyleName(Button.STYLE_LINK);
+ logo.addStyleName("logo");
+ logo.setIcon(new ThemeResource("sampler/sampler.png"));
+ return logo;
+ }
+
+ private Button createNextButton() {
+ Button b = new Button("", new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Object curr = currentFeature.getValue();
+ Object next = allFeatures.nextItemId(curr);
+ while (next != null && next instanceof FeatureSet) {
+ next = allFeatures.nextItemId(next);
+ }
+ if (next != null) {
+ currentFeature.setValue(next);
+ } else {
+ // could potentially occur if there is an empty section
+ showNotification("Last sample");
+ }
+ }
+ });
+ b.setStyleName("next");
+ b.setDescription("Jump to the next sample");
+ return b;
+ }
+
+ private Button createPrevButton() {
+ Button b = new Button("", new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Object curr = currentFeature.getValue();
+ Object prev = allFeatures.prevItemId(curr);
+ while (prev != null && prev instanceof FeatureSet) {
+ prev = allFeatures.prevItemId(prev);
+ }
+ currentFeature.setValue(prev);
+ }
+ });
+ b.setEnabled(false);
+ b.setStyleName("previous");
+ b.setDescription("Jump to the previous sample");
+ return b;
+ }
+
+ private Component createTreeSwitch() {
+ final Button b = new Button();
+ b.setStyleName("tree-switch");
+ b.setDescription("Toggle sample tree visibility");
+ b.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (b.getStyleName().contains("down")) {
+ b.removeStyleName("down");
+ mainSplit.setSplitPosition(0);
+ navigationTree.setVisible(false);
+ mainSplit.setLocked(true);
+ } else {
+ b.addStyleName("down");
+ mainSplit.setSplitPosition(20);
+ mainSplit.setLocked(false);
+ navigationTree.setVisible(true);
+ }
+ }
+ });
+ mainSplit.setSplitPosition(0);
+ navigationTree.setVisible(false);
+ mainSplit.setLocked(true);
+ return b;
+ }
+
+ private ModeSwitch createModeSwitch() {
+ ModeSwitch m = new ModeSwitch();
+ m.addMode(currentList, "", "View as Icons", new ThemeResource(
+ "sampler/grid.png"));
+ /*- no CoverFlow yet
+ m.addMode(coverFlow, "", "View as Icons", new ThemeResource(
+ "sampler/flow.gif"));
+ */
+ m.addMode(new FeatureTable(), "", "View as List",
+ new ThemeResource("sampler/list.png"));
+ m.addListener(new ModeSwitch.ModeSwitchListener() {
+ public void componentEvent(Event event) {
+ if (event instanceof ModeSwitchEvent) {
+ updateFeatureList((FeatureList) ((ModeSwitchEvent) event)
+ .getMode());
+ }
+ }
+ });
+ return m;
+ }
+
+ private Tree createMenuTree() {
+ final Tree tree = new Tree();
+ tree.setImmediate(true);
+ tree.setStyleName("menu");
+ tree.setContainerDataSource(allFeatures);
+ currentFeature.addListener(new Property.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ Feature f = (Feature) event.getProperty().getValue();
+ Feature v = (Feature) tree.getValue();
+ if ((f != null && !f.equals(v)) || (f == null && v != null)) {
+ tree.setValue(f);
+ }
+ }
+ });
+ for (int i = 0; i < FeatureSet.FEATURES.getFeatures().length; i++) {
+ tree
+ .expandItemsRecursively(FeatureSet.FEATURES
+ .getFeatures()[i]);
+ }
+ tree.expandItemsRecursively(FeatureSet.FEATURES);
+ tree.addListener(new Tree.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ Feature f = (Feature) event.getProperty().getValue();
+ setFeature(f);
+ }
+ });
+ return tree;
+ }
+
+ private void updateFeatureList(FeatureList list) {
+ currentList = list;
+ Feature val = (Feature) currentFeature.getValue();
+ if (val == null) {
+ currentList.setFeatureContainer(allFeatures);
+ mainSplit.setSecondComponent(currentList);
+ mode.setVisible(true);
+ } else if (val instanceof FeatureSet) {
+ currentList.setFeatureContainer(((FeatureSet) val)
+ .getContainer(true));
+ mainSplit.setSecondComponent(currentList);
+ mode.setVisible(true);
+ } else {
+ mainSplit.setSecondComponent(featureView);
+ featureView.setFeature(val);
+ mode.setVisible(false);
+ }
+
+ }
+
+ }
+
+ private class BreadCrumbs extends CustomComponent implements
+ ActiveLink.LinkActivatedListener {
+ HorizontalLayout layout;
+
+ BreadCrumbs() {
+ layout = new HorizontalLayout();
+ layout.setSpacing(true);
+ setCompositionRoot(layout);
+ setStyleName("breadcrumbs");
+ setPath(null);
+ }
+
+ public void setPath(String path) {
+ // could be optimized: always builds path from scratch
+ layout.removeAllComponents();
+
+ { // home
+ ActiveLink link = new ActiveLink("Home", new ExternalResource(
+ "#"));
+ link.addListener(this);
+ layout.addComponent(link);
+ }
+
+ if (path != null && !"".equals(path)) {
+ String parts[] = path.split("/");
+ String current = "";
+ ActiveLink link = null;
+ for (int i = 0; i < parts.length; i++) {
+ layout.addComponent(new Label("&raquo;",
+ Label.CONTENT_XHTML));
+ current += (i > 0 ? "/" : "") + parts[i];
+ Feature f = FeatureSet.FEATURES.getFeatureByPath(current);
+ link = new ActiveLink(f.getName(), new ExternalResource("#"
+ + getPathFor(f)));
+ link.setData(f);
+ link.addListener(this);
+ layout.addComponent(link);
+ }
+ if (link != null) {
+ link.setStyleName("bold");
+ }
+ }
+
+ }
+
+ public void linkActivated(LinkActivatedEvent event) {
+ if (!event.isLinkOpened()) {
+ ((SamplerWindow) getWindow()).setFeature((Feature) event
+ .getActiveLink().getData());
+ }
+ }
+ }
+
+ /**
+ * Components capable of listing Features should implement this.
+ *
+ */
+ interface FeatureList extends Component {
+ /**
+ * Shows the given Features
+ *
+ * @param c
+ * Container with Features to show.
+ */
+ public void setFeatureContainer(HierarchicalContainer c);
+ }
+
+ /**
+ * Table -mode FeatureList. Displays the features in a Table.
+ */
+ private class FeatureTable extends Table implements FeatureList {
+ private HashMap<Object, Resource> iconCache = new HashMap<Object, Resource>();
+
+ FeatureTable() {
+ setStyleName("featuretable");
+ alwaysRecalculateColumnWidths = true;
+ setSelectable(false);
+ setSizeFull();
+ setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN);
+ addGeneratedColumn(Feature.PROPERTY_ICON,
+ new Table.ColumnGenerator() {
+ public Component generateCell(Table source,
+ Object itemId, Object columnId) {
+ Feature f = (Feature) itemId;
+ if (f instanceof FeatureSet) {
+ // no icon for sections
+ return null;
+ }
+ String resId = "75-" + f.getIconName();
+ Resource res = iconCache.get(resId);
+ if (res == null) {
+ res = new ClassResource(f.getClass(), resId,
+ SamplerApplication.this);
+ iconCache.put(resId, res);
+
+ }
+ Embedded emb = new Embedded("", res);
+ emb.setWidth("48px");
+ emb.setHeight("48px");
+ emb.setType(Embedded.TYPE_IMAGE);
+ return emb;
+ }
+
+ });
+ addGeneratedColumn("", new Table.ColumnGenerator() {
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ final Feature feature = (Feature) itemId;
+ if (feature instanceof FeatureSet) {
+ return null;
+ } else {
+ ActiveLink b = new ActiveLink("View sample ‣",
+ new ExternalResource("#" + getPathFor(feature)));
+ b.addListener(new ActiveLink.LinkActivatedListener() {
+ public void linkActivated(LinkActivatedEvent event) {
+ if (!event.isLinkOpened()) {
+ ((SamplerWindow) getWindow())
+ .setFeature(feature);
+ }
+ }
+ });
+
+ b.setStyleName(Button.STYLE_LINK);
+ return b;
+ }
+ }
+
+ });
+
+ addListener(new ItemClickListener() {
+ public void itemClick(ItemClickEvent event) {
+ Feature f = (Feature) event.getItemId();
+ if (event.getButton() == ItemClickEvent.BUTTON_MIDDLE
+ || event.isCtrlKey() || event.isShiftKey()) {
+ getWindow().open(
+ new ExternalResource(getURL() + "#"
+ + getPathFor(f)), "_blank");
+ } else {
+ ((SamplerWindow) getWindow()).setFeature(f);
+ }
+ }
+ });
+
+ setCellStyleGenerator(new CellStyleGenerator() {
+ public String getStyle(Object itemId, Object propertyId) {
+ if (propertyId == null && itemId instanceof FeatureSet) {
+ if (allFeatures.isRoot(itemId)) {
+ return "section";
+ } else {
+ return "subsection";
+ }
+
+ }
+ return null;
+ }
+ });
+ }
+
+ public void setFeatureContainer(HierarchicalContainer c) {
+ setContainerDataSource(c);
+ setVisibleColumns(new Object[] { Feature.PROPERTY_ICON,
+ Feature.PROPERTY_NAME, "" });
+ setColumnWidth(Feature.PROPERTY_ICON, 60);
+
+ }
+
+ }
+
+ private class FeatureGrid extends Panel implements FeatureList {
+
+ GridLayout grid = new GridLayout(11, 1);
+ private HashMap<Object, Resource> iconCache = new HashMap<Object, Resource>();
+
+ FeatureGrid() {
+ setSizeFull();
+ setLayout(grid);
+ grid.setSizeUndefined();
+ grid.setSpacing(true);
+ setStyleName(Panel.STYLE_LIGHT);
+ }
+
+ public void setFeatureContainer(HierarchicalContainer c) {
+ grid.removeAllComponents();
+ Collection features = c.getItemIds();
+ for (Iterator it = features.iterator(); it.hasNext();) {
+ final Feature f = (Feature) it.next();
+ if (f instanceof FeatureSet) {
+ grid.newLine();
+ Label title = new Label(f.getName());
+ if (c.isRoot(f)) {
+ title.setWidth("100%");
+ title.setStyleName("section");
+ grid.setRows(grid.getCursorY() + 1);
+ grid.addComponent(title, 0, grid.getCursorY(), grid
+ .getColumns() - 1, grid.getCursorY());
+ grid
+ .setComponentAlignment(title,
+ Alignment.MIDDLE_LEFT);
+ } else {
+ title.setStyleName("subsection");
+ grid.addComponent(title);
+ grid
+ .setComponentAlignment(title,
+ Alignment.MIDDLE_LEFT);
+ }
+
+ } else {
+ if (grid.getCursorX() == 0) {
+ grid.space();
+ }
+ Button b = new Button();
+ b.setStyleName(Button.STYLE_LINK);
+ b.addStyleName("screenshot");
+ String resId = "75-" + f.getIconName();
+ Resource res = iconCache.get(resId);
+ if (res == null) {
+ res = new ClassResource(f.getClass(), resId,
+ SamplerApplication.this);
+ iconCache.put(resId, res);
+
+ }
+ b.setIcon(res);
+ b.setWidth("75px");
+ b.setHeight("75px");
+ b.setDescription("<h3>" + f.getName() + "</h3>");
+ b.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ ((SamplerWindow) getWindow()).setFeature(f);
+ }
+ });
+ grid.addComponent(b);
+ }
+ }
+ }
+ }
+
+ public static HierarchicalContainer getAllFeatures() {
+ return allFeatures;
+ }
+
+ public class SourceWindow extends Window {
+ public SourceWindow() {
+ addURIHandler(new URIHandler() {
+ public DownloadStream handleURI(URL context, String relativeUri) {
+ Feature f = FeatureSet.FEATURES
+ .getFeatureByPath(relativeUri);
+ if (f != null) {
+ addComponent(new CodeLabel(f.getSource()));
+ } else {
+ addComponent(new Label("Sorry, no source found for "
+ + relativeUri));
+ }
+ return null;
+ }
+
+ });
+
+ addListener(new CloseListener() {
+ public void windowClose(CloseEvent e) {
+ SamplerApplication.this.removeWindow(SourceWindow.this);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void close() {
+ removeWindow(getMainWindow());
+
+ super.close();
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/accordions/75-AccordionDisabled.png b/src/com/vaadin/demo/sampler/features/accordions/75-AccordionDisabled.png
new file mode 100644
index 0000000000..fb3e3fe844
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/accordions/75-AccordionDisabled.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/accordions/75-AccordionIcons.png b/src/com/vaadin/demo/sampler/features/accordions/75-AccordionIcons.png
new file mode 100644
index 0000000000..c38a1aefc8
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/accordions/75-AccordionIcons.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/accordions/AccordionDisabled.java b/src/com/vaadin/demo/sampler/features/accordions/AccordionDisabled.java
new file mode 100644
index 0000000000..b9be6b4add
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/accordions/AccordionDisabled.java
@@ -0,0 +1,36 @@
+package com.vaadin.demo.sampler.features.accordions;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Accordion;
+
+public class AccordionDisabled extends Feature {
+ @Override
+ public String getName() {
+ return "Accordion, disabled tabs";
+ }
+
+ @Override
+ public String getDescription() {
+ return "You can disable, enable, hide and show accordion 'tabs'.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Accordion.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { AccordionIcons.class, FeatureSet.Tabsheets.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/accordions/AccordionDisabledExample.java b/src/com/vaadin/demo/sampler/features/accordions/AccordionDisabledExample.java
new file mode 100644
index 0000000000..ae8e817ade
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/accordions/AccordionDisabledExample.java
@@ -0,0 +1,87 @@
+package com.vaadin.demo.sampler.features.accordions;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Accordion;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
+import com.vaadin.ui.TabSheet.Tab;
+
+public class AccordionDisabledExample extends VerticalLayout implements
+ Accordion.SelectedTabChangeListener, Button.ClickListener {
+
+ private Accordion a;
+ private Button b1;
+ private Button b2;
+ private Label l1;
+ private Label l2;
+ private Label l3;
+ private Tab t1;
+ private Tab t2;
+ private Tab t3;
+
+ private static final ThemeResource icon1 = new ThemeResource(
+ "icons/action_save.gif");
+ private static final ThemeResource icon2 = new ThemeResource(
+ "icons/comment_yellow.gif");
+ private static final ThemeResource icon3 = new ThemeResource(
+ "icons/icon_info.gif");
+
+ public AccordionDisabledExample() {
+ setSpacing(true);
+
+ l1 = new Label("There are no previously saved actions.");
+ l2 = new Label("There are no saved notes.");
+ l3 = new Label("There are currently no issues.");
+
+ a = new Accordion();
+ a.setHeight("300px");
+ a.setWidth("400px");
+ t1 = a.addTab(l1, "Saved actions", icon1);
+ t2 = a.addTab(l2, "Notes", icon2);
+ t3 = a.addTab(l3, "Issues", icon3);
+ a.addListener(this);
+
+ b1 = new Button("Disable 'Notes' tab");
+ b2 = new Button("Hide 'Issues' tab");
+ b1.addListener(this);
+ b2.addListener(this);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setSpacing(true);
+ hl.addComponent(b1);
+ hl.addComponent(b2);
+
+ addComponent(a);
+ addComponent(hl);
+ }
+
+ public void selectedTabChange(SelectedTabChangeEvent event) {
+ String c = a.getTab(event.getTabSheet().getSelectedTab()).getCaption();
+ getWindow().showNotification("Selected tab: " + c);
+ }
+
+ public void buttonClick(ClickEvent event) {
+ if (b1.equals(event.getButton())) { // b1 clicked
+ if (t2.isEnabled()) {
+ t2.setEnabled(false);
+ b1.setCaption("Enable 'Notes' tab");
+ } else {
+ t2.setEnabled(true);
+ b1.setCaption("Disable 'Notes' tab");
+ }
+ } else { // b2 clicked
+ if (t3.isVisible()) {
+ t3.setVisible(false);
+ b2.setCaption("Show 'Issues' tab");
+ } else {
+ t3.setVisible(true);
+ b2.setCaption("Hide 'Issues' tab");
+ }
+ }
+ a.requestRepaint();
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/accordions/AccordionIcons.java b/src/com/vaadin/demo/sampler/features/accordions/AccordionIcons.java
new file mode 100644
index 0000000000..d6f0cf9e48
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/accordions/AccordionIcons.java
@@ -0,0 +1,37 @@
+package com.vaadin.demo.sampler.features.accordions;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Accordion;
+
+public class AccordionIcons extends Feature {
+ @Override
+ public String getName() {
+ return "Accordion with icons";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The accordion 'tabs' can contain icons in addition to the caption.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Accordion.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { AccordionDisabled.class,
+ FeatureSet.Tabsheets.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/accordions/AccordionIconsExample.java b/src/com/vaadin/demo/sampler/features/accordions/AccordionIconsExample.java
new file mode 100644
index 0000000000..42047581a0
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/accordions/AccordionIconsExample.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.accordions;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Accordion;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
+
+public class AccordionIconsExample extends HorizontalLayout implements
+ Accordion.SelectedTabChangeListener {
+
+ private static final ThemeResource icon1 = new ThemeResource(
+ "icons/action_save.gif");
+ private static final ThemeResource icon2 = new ThemeResource(
+ "icons/comment_yellow.gif");
+ private static final ThemeResource icon3 = new ThemeResource(
+ "icons/icon_info.gif");
+
+ private Accordion a;
+
+ public AccordionIconsExample() {
+ setSpacing(true);
+
+ Label l1 = new Label("There are no previously saved actions.");
+ Label l2 = new Label("There are no saved notes.");
+ Label l3 = new Label("There are currently no issues.");
+
+ a = new Accordion();
+ a.setHeight("300px");
+ a.setWidth("400px");
+ a.addTab(l1, "Saved actions", icon1);
+ a.addTab(l2, "Notes", icon2);
+ a.addTab(l3, "Issues", icon3);
+ a.addListener(this);
+
+ addComponent(a);
+ }
+
+ public void selectedTabChange(SelectedTabChangeEvent event) {
+ String c = a.getTabCaption(event.getTabSheet().getSelectedTab());
+ getWindow().showNotification("Selected tab: " + c);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/blueprints/75-ProminentPrimaryAction.png b/src/com/vaadin/demo/sampler/features/blueprints/75-ProminentPrimaryAction.png
new file mode 100644
index 0000000000..d249324e0c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/blueprints/75-ProminentPrimaryAction.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryAction.java b/src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryAction.java
new file mode 100644
index 0000000000..d3eaa06d8b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryAction.java
@@ -0,0 +1,55 @@
+package com.vaadin.demo.sampler.features.blueprints;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.buttons.ButtonLink;
+import com.vaadin.demo.sampler.features.buttons.ButtonPush;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Link;
+
+public class ProminentPrimaryAction extends Feature {
+
+ @Override
+ public String getName() {
+ return "Prominent primary action";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A primary action is an action that is clearly the"
+ + " default, and it should be visually more prominent"
+ + " than the secondary actions.<br/>Good candidates"
+ + " include <i>Save</i>, <i>Submit</i>, <i>Continue</i>, <i>Next</i>,"
+ + " <i>Finish</i> and so on.<br/>Note that 'dangerous' actions"
+ + " that can not be undone should not be primary, and that it's"
+ + " not always possible to identify a primary action"
+ + " - don't force it if it's not obvious.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Button.class),
+ new APIResource(Link.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ButtonPush.class, ButtonLink.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] {
+
+ new NamedExternalResource("CSS for 'Sign up' button",
+ getThemeBase() + "prominentprimaryaction/styles.css"),
+
+ new NamedExternalResource(
+ "Article: Primary & Secondary Actions in Web Forms (LukeW)",
+ "http://www.lukew.com/resources/articles/psactions.asp"),
+ new NamedExternalResource(
+ "Article: Primary & Secondary Actions (UI Pattern Factory)",
+ "http://uipatternfactory.com/p=primary-and-secondary-actions/") };
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryActionExample.java b/src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryActionExample.java
new file mode 100644
index 0000000000..bbbb3d6b6a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/blueprints/ProminentPrimaryActionExample.java
@@ -0,0 +1,68 @@
+package com.vaadin.demo.sampler.features.blueprints;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class ProminentPrimaryActionExample extends VerticalLayout implements
+ Button.ClickListener {
+
+ public ProminentPrimaryActionExample() {
+ setSpacing(true);
+
+ { // Cancel / Save
+ HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setCaption("Save/cancel example:");
+ horiz.setSpacing(true);
+ horiz.setMargin(true);
+ addComponent(horiz);
+ Button secondary = new Button("Cancel", this);
+ secondary.setStyleName(Button.STYLE_LINK);
+ horiz.addComponent(secondary);
+ Button primary = new Button("Save", this);
+ horiz.addComponent(primary);
+ }
+
+ { // Sign up / Sign in
+ HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setCaption("Sign up example:");
+ horiz.setSpacing(true);
+ horiz.setMargin(true);
+ addComponent(horiz);
+ Button primary = new Button("Sign up", this);
+ primary.addStyleName("primary");
+ horiz.addComponent(primary);
+ Button secondary = new Button("or Sign in", this);
+ secondary.setStyleName(Button.STYLE_LINK);
+ horiz.addComponent(secondary);
+ horiz.setComponentAlignment(secondary, Alignment.MIDDLE_LEFT);
+ }
+
+ { // Login / Forgot password?
+ VerticalLayout vert = new VerticalLayout();
+ vert.setCaption("Login example:");
+ vert.setSizeUndefined();
+ vert.setSpacing(true);
+ vert.setMargin(true);
+ addComponent(vert);
+ Button primary = new Button("Login", this);
+ vert.addComponent(primary);
+ vert.setComponentAlignment(primary, Alignment.BOTTOM_RIGHT);
+ Button secondary = new Button("Forgot your password?", this);
+ secondary.setStyleName(Button.STYLE_LINK);
+ vert.addComponent(secondary);
+ vert.setComponentAlignment(secondary, Alignment.BOTTOM_RIGHT);
+ }
+
+ }
+
+ /*
+ * Shows a notification when a button is clicked.
+ */
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ "\"" + event.getButton().getCaption() + "\" clicked");
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/buttons/75-ButtonLink.png b/src/com/vaadin/demo/sampler/features/buttons/75-ButtonLink.png
new file mode 100644
index 0000000000..4e6963f8d1
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/75-ButtonLink.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/buttons/75-ButtonPush.png b/src/com/vaadin/demo/sampler/features/buttons/75-ButtonPush.png
new file mode 100644
index 0000000000..6520e205ff
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/75-ButtonPush.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/buttons/75-ButtonSwitch.png b/src/com/vaadin/demo/sampler/features/buttons/75-ButtonSwitch.png
new file mode 100644
index 0000000000..6df1b3935d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/75-ButtonSwitch.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/buttons/ButtonLink.java b/src/com/vaadin/demo/sampler/features/buttons/ButtonLink.java
new file mode 100644
index 0000000000..f9f73852bf
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/ButtonLink.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.buttons;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.blueprints.ProminentPrimaryAction;
+import com.vaadin.demo.sampler.features.link.LinkCurrentWindow;
+import com.vaadin.ui.Button;
+
+public class ButtonLink extends Feature {
+
+ @Override
+ public String getName() {
+ return "Link button";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A link-styled button works like a push button, but looks like"
+ + " a Link.<br/> It does not actually link somewhere, but"
+ + " triggers a server-side event, just like a regular button.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Button.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ButtonPush.class, ButtonSwitch.class,
+ LinkCurrentWindow.class, ProminentPrimaryAction.class,
+ FeatureSet.Links.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/buttons/ButtonLinkExample.java b/src/com/vaadin/demo/sampler/features/buttons/ButtonLinkExample.java
new file mode 100644
index 0000000000..4b2e00ea7a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/ButtonLinkExample.java
@@ -0,0 +1,51 @@
+package com.vaadin.demo.sampler.features.buttons;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class ButtonLinkExample extends VerticalLayout implements
+ Button.ClickListener {
+
+ private static final String CAPTION = "Help";
+ private static final String TOOLTIP = "Show help";
+ private static final ThemeResource ICON = new ThemeResource(
+ "icons/icon_info.gif");
+ private static final String NOTIFICATION = "Help clicked";
+
+ public ButtonLinkExample() {
+ setSpacing(true);
+
+ // Button w/ text and tooltip
+ Button b = new Button(CAPTION);
+ b.setStyleName(Button.STYLE_LINK);
+ b.setDescription(TOOLTIP);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ // Button w/ text, icon and tooltip
+ b = new Button(CAPTION);
+ b.setStyleName(Button.STYLE_LINK);
+ b.setDescription(TOOLTIP);
+ b.setIcon(ICON);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ // Button w/ icon and tooltip
+ b = new Button();
+ b.setStyleName(Button.STYLE_LINK);
+ b.setDescription(TOOLTIP);
+ b.setIcon(ICON);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ }
+
+ /*
+ * Shows a notification when a button is clicked.
+ */
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(NOTIFICATION);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/buttons/ButtonPush.java b/src/com/vaadin/demo/sampler/features/buttons/ButtonPush.java
new file mode 100644
index 0000000000..4b9dc23480
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/ButtonPush.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.features.buttons;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.blueprints.ProminentPrimaryAction;
+import com.vaadin.ui.Button;
+
+public class ButtonPush extends Feature {
+
+ @Override
+ public String getName() {
+ return "Push button";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A push-button, which can be considered a 'regular' button,"
+ + " returns to it's 'unclicked' state after emitting an event"
+ + " when the user clicks it.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Button.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ButtonLink.class, ButtonSwitch.class,
+ ProminentPrimaryAction.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/buttons/ButtonPushExample.java b/src/com/vaadin/demo/sampler/features/buttons/ButtonPushExample.java
new file mode 100644
index 0000000000..67d6e61b60
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/ButtonPushExample.java
@@ -0,0 +1,48 @@
+package com.vaadin.demo.sampler.features.buttons;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class ButtonPushExample extends VerticalLayout implements
+ Button.ClickListener {
+
+ private static final String CAPTION = "Save";
+ private static final String TOOLTIP = "Save changes";
+ private static final ThemeResource ICON = new ThemeResource(
+ "icons/action_save.gif");
+ private static final String NOTIFICATION = "Changes have been saved";
+
+ public ButtonPushExample() {
+ setSpacing(true);
+
+ // Button w/ text and tooltip
+ Button b = new Button(CAPTION);
+ b.setDescription(TOOLTIP);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ // Button w/ text, icon and tooltip
+ b = new Button(CAPTION);
+ b.setDescription(TOOLTIP);
+ b.setIcon(ICON);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ // Button w/ icon and tooltip
+ b = new Button();
+ b.setDescription(TOOLTIP);
+ b.setIcon(ICON);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ }
+
+ /*
+ * Shows a notification when a button is clicked.
+ */
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(NOTIFICATION);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/buttons/ButtonSwitch.java b/src/com/vaadin/demo/sampler/features/buttons/ButtonSwitch.java
new file mode 100644
index 0000000000..4a86668f62
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/ButtonSwitch.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.buttons;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Button;
+
+public class ButtonSwitch extends Feature {
+
+ @Override
+ public String getName() {
+ return "Switch button";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A switch button works like a regular push button, triggering"
+ + " a server-side event, but it's state is 'sticky': the button"
+ + " toggles between it's on and off states, instead of popping"
+ + " right back out.<br/>Also know as a CheckBox.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Button.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ButtonPush.class, ButtonLink.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/buttons/ButtonSwitchExample.java b/src/com/vaadin/demo/sampler/features/buttons/ButtonSwitchExample.java
new file mode 100644
index 0000000000..5bc0442ce4
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/buttons/ButtonSwitchExample.java
@@ -0,0 +1,52 @@
+package com.vaadin.demo.sampler.features.buttons;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class ButtonSwitchExample extends VerticalLayout implements
+ Button.ClickListener {
+
+ private static final String CAPTION = "Allow HTML";
+ private static final String TOOLTIP = "Allow/disallow HTML in comments";
+ private static final ThemeResource ICON = new ThemeResource(
+ "icons/page_code.gif");
+
+ public ButtonSwitchExample() {
+ setSpacing(true);
+
+ // Button w/ text and tooltip
+ Button b = new Button(CAPTION);
+ b.setSwitchMode(true);
+ b.setDescription(TOOLTIP);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ // Button w/ text, icon and tooltip
+ b = new Button(CAPTION);
+ b.setSwitchMode(true);
+ b.setDescription(TOOLTIP);
+ b.setIcon(ICON);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ // Button w/ icon and tooltip
+ b = new Button();
+ b.setSwitchMode(true);
+ b.setDescription(TOOLTIP);
+ b.setIcon(ICON);
+ b.addListener(this); // react to clicks
+ addComponent(b);
+
+ }
+
+ /*
+ * Shows a notification when a button is clicked.
+ */
+ public void buttonClick(ClickEvent event) {
+ boolean enabled = event.getButton().booleanValue();
+ getWindow().showNotification(
+ "HTML " + (enabled ? "enabled" : "disabled"));
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/75-Errors.png b/src/com/vaadin/demo/sampler/features/commons/75-Errors.png
new file mode 100644
index 0000000000..26b29ce24f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/75-Errors.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/commons/75-Icons.png b/src/com/vaadin/demo/sampler/features/commons/75-Icons.png
new file mode 100644
index 0000000000..23c733579b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/75-Icons.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/commons/75-Tooltips.png b/src/com/vaadin/demo/sampler/features/commons/75-Tooltips.png
new file mode 100644
index 0000000000..217daeb920
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/75-Tooltips.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/commons/75-Validation.png b/src/com/vaadin/demo/sampler/features/commons/75-Validation.png
new file mode 100644
index 0000000000..058ec7db9f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/75-Validation.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/commons/Errors.java b/src/com/vaadin/demo/sampler/features/commons/Errors.java
new file mode 100644
index 0000000000..5cac780621
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/Errors.java
@@ -0,0 +1,52 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.form.FormBasic;
+import com.vaadin.demo.sampler.features.notifications.NotificationError;
+import com.vaadin.ui.AbstractComponent;
+
+public class Errors extends Feature {
+
+ private static final String desc = "A <i>component error</i> can be set to"
+ + " indicate an error - an error indicator icon will appear,"
+ + " and the error message will appear as a 'tooltip' when"
+ + " mousing over.<br/>"
+ + "You can do this on almost any component, but please note"
+ + " that from a usability standpoint it's not always the best"
+ + " solution.<br/>"
+ + "<i>Component error</i> is most useful to indicate what is"
+ + " causing the error (e.g an 'email' TextField), so that the user"
+ + " can find and correct the problem. <br/>"
+ + "On the other hand, it is usually not a good idea to set an error"
+ + " on a Button: the user can not click 'Save' differently to"
+ + " correct the error.<br/>"
+ + "If there is no component causing the error, consider using a"
+ + " (styled) Label or a Notification to indicate the error.";
+
+ @Override
+ public String getName() {
+ return "Error indicator";
+ }
+
+ public String getDescription() {
+ return desc;
+ }
+
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(AbstractComponent.class) };
+ }
+
+ public Class[] getRelatedFeatures() {
+ // TODO link validation sample, form sample
+ return new Class[] { Validation.class, FormBasic.class,
+ NotificationError.class };
+ }
+
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/ErrorsExample.java b/src/com/vaadin/demo/sampler/features/commons/ErrorsExample.java
new file mode 100644
index 0000000000..fc5b1eff24
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/ErrorsExample.java
@@ -0,0 +1,24 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import com.vaadin.terminal.UserError;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class ErrorsExample extends VerticalLayout {
+
+ public ErrorsExample() {
+ setSpacing(true);
+
+ Panel panel = new Panel("Configure this");
+ panel.setComponentError(new UserError("'Input' contains an error"));
+ addComponent(panel);
+
+ TextField input = new TextField("Input");
+ input
+ .setComponentError(new UserError(
+ "This field is never satisfied."));
+ panel.addComponent(input);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/Icons.java b/src/com/vaadin/demo/sampler/features/commons/Icons.java
new file mode 100644
index 0000000000..0baf8fca6e
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/Icons.java
@@ -0,0 +1,55 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.terminal.ApplicationResource;
+import com.vaadin.terminal.ClassResource;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.FileResource;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.StreamResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Component;
+
+public class Icons extends Feature {
+
+ @Override
+ public String getName() {
+ return "Icons";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Most components can have an <i>icon</i>,"
+ + " which is usually displayed next to the caption.<br/>"
+ + "When used correctly, icons can make it significantly"
+ + " easier for the user to find a specific functionality."
+ + " Beware of overuse, which will have the opposite effect.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Component.class),
+ new APIResource(Resource.class),
+ new APIResource(ApplicationResource.class),
+ new APIResource(ClassResource.class),
+ new APIResource(ExternalResource.class),
+ new APIResource(FileResource.class),
+ new APIResource(StreamResource.class),
+ new APIResource(ThemeResource.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ // TODO link embedded sample
+ return null;
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/IconsExample.java b/src/com/vaadin/demo/sampler/features/commons/IconsExample.java
new file mode 100644
index 0000000000..39d31dbfcf
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/IconsExample.java
@@ -0,0 +1,49 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+
+public class IconsExample extends VerticalLayout {
+
+ public IconsExample() {
+ setSpacing(true);
+
+ /* Button w/ icon */
+ Button button = new Button("Save");
+ button.setIcon(new ThemeResource("icons/action_save.gif"));
+ addComponent(button);
+
+ /* Label */;
+ Label l = new Label("Icons are very handy");
+ l.setCaption("Comment");
+ l.setIcon(new ThemeResource("icons/comment_yellow.gif"));
+ addComponent(l);
+
+ /* Panel w/ links */
+ Panel p = new Panel("Handy links");
+ p.setIcon(new ThemeResource("icons/icon_info.gif"));
+ addComponent(p);
+ Link lnk = new Link("http://www.itmill.com", new ExternalResource(
+ "http://www.itmill.com"));
+ lnk.setIcon(new ThemeResource("icons/icon_world.gif"));
+ p.addComponent(lnk);
+ lnk = new Link("http://www.itmill.com/developers/",
+ new ExternalResource("http://www.itmill.com/developers/"));
+ lnk.setIcon(new ThemeResource("icons/icon_world.gif"));
+ p.addComponent(lnk);
+ lnk = new Link("http://dev.itmill.com/", new ExternalResource(
+ "http://dev.itmill.com/"));
+ lnk.setIcon(new ThemeResource("icons/icon_world.gif"));
+ p.addComponent(lnk);
+ lnk = new Link("http://forum.itmill.com", new ExternalResource(
+ "http://forum.itmill.com"));
+ lnk.setIcon(new ThemeResource("icons/icon_world.gif"));
+ p.addComponent(lnk);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/Tooltips.java b/src/com/vaadin/demo/sampler/features/commons/Tooltips.java
new file mode 100644
index 0000000000..eac86146fe
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/Tooltips.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.AbstractComponent;
+
+public class Tooltips extends Feature {
+
+ @Override
+ public String getName() {
+ return "Tooltips";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Most components can have a <i>description</i>,"
+ + " which is shown as a <i>\"tooltip\"</i>."
+ + " Descriptions may have formatted ('rich') content.<br/>"
+ + "";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(AbstractComponent.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/TooltipsExample.java b/src/com/vaadin/demo/sampler/features/commons/TooltipsExample.java
new file mode 100644
index 0000000000..932286df76
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/TooltipsExample.java
@@ -0,0 +1,56 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class TooltipsExample extends VerticalLayout {
+
+ private static final String editTxt = "Edit tooltip";
+ private static final String applyTxt = "Apply";
+
+ public TooltipsExample() {
+ setSpacing(true);
+
+ /* Plain tooltip (description) */
+ Button plain = new Button("Mouse over for plain tooltip");
+ plain.setStyleName(Button.STYLE_LINK);
+ // add the tooltip:
+ plain.setDescription("A simple plaintext tooltip");
+ addComponent(plain);
+
+ /* Richtext tooltip (description) */
+ Button rich = new Button("Mouse over for richtext tooltip");
+ rich.setStyleName(Button.STYLE_LINK);
+ // add the tooltip:
+ rich
+ .setDescription("<h2><img src=\"../ITMILL/themes/sampler/icons/comment_yellow.gif\"/>A richtext tooltip</h2>"
+ + "<ul>"
+ + "<li>HTML formatting</li><li>Images<br/>"
+ + "</li><li>etc...</li></ul>");
+ addComponent(rich);
+
+ /* Edit */
+ final RichTextArea rte = new RichTextArea();
+ rte.setValue("Click <b>" + editTxt
+ + "</b> to edit this tooltip, then <b>" + applyTxt + "</b>");
+ rte.setVisible(false); // hide editor initially
+ addComponent(rte);
+ Button apply = new Button(editTxt, new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (rte.isVisible()) {
+ rte.setVisible(false);
+ event.getButton().setDescription((String) rte.getValue());
+ event.getButton().setCaption(editTxt);
+ } else {
+ rte.setVisible(true);
+ event.getButton().setCaption(applyTxt);
+ }
+ }
+ });
+ apply.setDescription((String) rte.getValue());
+ addComponent(apply);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/Validation.java b/src/com/vaadin/demo/sampler/features/commons/Validation.java
new file mode 100644
index 0000000000..3ff516a5ba
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/Validation.java
@@ -0,0 +1,46 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import com.vaadin.data.Validatable;
+import com.vaadin.data.Validator;
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.form.FormPojoExample;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Form;
+
+public class Validation extends Feature {
+
+ @Override
+ public String getName() {
+ return "Validation";
+ }
+
+ private static final String desc = "Fields can have Validators that check"
+ + " entered values. This is most useful when used within a Form, but"
+ + " but can be used to validate single, stand-alone Fields as well.";
+
+ @Override
+ public Component getExample() {
+ return new FormPojoExample();
+ }
+
+ public String getDescription() {
+ return desc;
+ }
+
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Validatable.class),
+ new APIResource(Validator.class), new APIResource(Form.class) };
+ }
+
+ public Class[] getRelatedFeatures() {
+ return new Class[] { Errors.class, FeatureSet.Forms.class };
+ }
+
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/commons/ValidationExample.java b/src/com/vaadin/demo/sampler/features/commons/ValidationExample.java
new file mode 100644
index 0000000000..873b641ec7
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/commons/ValidationExample.java
@@ -0,0 +1,62 @@
+package com.vaadin.demo.sampler.features.commons;
+
+import java.util.HashSet;
+
+import com.vaadin.data.Validator;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.validator.CompositeValidator;
+import com.vaadin.data.validator.StringLengthValidator;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class ValidationExample extends VerticalLayout {
+
+ HashSet usernames = new HashSet();
+
+ public ValidationExample() {
+ setSpacing(true);
+
+ TextField pin = new TextField("PIN");
+ pin.setWidth("50px");
+ // optional; validate at once instead of when clicking 'save' (e.g)
+ pin.setImmediate(true);
+ addComponent(pin);
+ // add the validator
+ pin.addValidator(new StringLengthValidator("Must be 4-6 characters", 4,
+ 6, false));
+
+ TextField username = new TextField("Username");
+ // optional; validate at once instead of when clicking 'save' (e.g)
+ username.setImmediate(true);
+ addComponent(username);
+ CompositeValidator usernameValidator = new CompositeValidator();
+ username.addValidator(usernameValidator);
+ usernameValidator.addValidator(new StringLengthValidator(
+ "Username must be at least 4 characters", 4, 255, false));
+ usernameValidator.addValidator(new Validator() {
+
+ public boolean isValid(Object value) {
+ return !usernames.contains(value);
+ }
+
+ public void validate(Object value) throws InvalidValueException {
+ if (!isValid(value)) {
+ throw new Validator.InvalidValueException("Username "
+ + value + " already in use");
+ }
+ }
+ });
+ username.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ TextField tf = (TextField) event.getProperty();
+ tf.validate();
+ usernames.add(tf.getValue());
+ addComponent(new Label("Added " + tf.getValue()
+ + " to usernames"));
+ }
+ });
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/75-DateInline.png b/src/com/vaadin/demo/sampler/features/dates/75-DateInline.png
new file mode 100644
index 0000000000..4368f420a9
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/75-DateInline.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/dates/75-DateLocale.png b/src/com/vaadin/demo/sampler/features/dates/75-DateLocale.png
new file mode 100644
index 0000000000..a608e59873
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/75-DateLocale.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/dates/75-DatePopup.png b/src/com/vaadin/demo/sampler/features/dates/75-DatePopup.png
new file mode 100644
index 0000000000..1030469dc2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/75-DatePopup.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/dates/75-DateResolution.png b/src/com/vaadin/demo/sampler/features/dates/75-DateResolution.png
new file mode 100644
index 0000000000..ca6ddcf16e
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/75-DateResolution.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/dates/DateInline.java b/src/com/vaadin/demo/sampler/features/dates/DateInline.java
new file mode 100644
index 0000000000..46a298f9d8
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DateInline.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.InlineDateField;
+
+public class DateInline extends Feature {
+ @Override
+ public String getName() {
+ return "Inline date selection";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, the resolution is set to be one day"
+ + " and the DateField component is shown as an inline calendar"
+ + " component.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(DateField.class),
+ new APIResource(InlineDateField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { DatePopup.class, DateLocale.class,
+ DateResolution.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/DateInlineExample.java b/src/com/vaadin/demo/sampler/features/dates/DateInlineExample.java
new file mode 100644
index 0000000000..5490b77a61
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DateInlineExample.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import java.text.DateFormat;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.VerticalLayout;
+
+public class DateInlineExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private InlineDateField datetime;
+
+ public DateInlineExample() {
+ setSpacing(true);
+
+ datetime = new InlineDateField("Please select the starting time:");
+
+ // Set the value of the PopupDateField to current date
+ datetime.setValue(new java.util.Date());
+
+ // Set the correct resolution
+ datetime.setResolution(InlineDateField.RESOLUTION_DAY);
+
+ // Add valuechangelistener
+ datetime.addListener(this);
+ datetime.setImmediate(true);
+
+ addComponent(datetime);
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ // Get the new value and format it to the current locale
+ DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.SHORT);
+ String dateOut = dateFormatter.format(event.getProperty().getValue());
+ // Show notification
+ getWindow().showNotification("Starting date: " + dateOut);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/DateLocale.java b/src/com/vaadin/demo/sampler/features/dates/DateLocale.java
new file mode 100644
index 0000000000..f150afcdfd
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DateLocale.java
@@ -0,0 +1,42 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import java.util.Locale;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.InlineDateField;
+
+public class DateLocale extends Feature {
+ @Override
+ public String getName() {
+ return "Date selection, locale";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, you can select a different locale"
+ + " from the combo box and see how the calendar component"
+ + " is localized.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(DateField.class),
+ new APIResource(InlineDateField.class),
+ new APIResource(Locale.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { DateInline.class, DatePopup.class,
+ DateResolution.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/DateLocaleExample.java b/src/com/vaadin/demo/sampler/features/dates/DateLocaleExample.java
new file mode 100644
index 0000000000..1e2e810b16
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DateLocaleExample.java
@@ -0,0 +1,48 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import java.util.Locale;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.VerticalLayout;
+
+public class DateLocaleExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private InlineDateField datetime;
+ private ComboBox localeSelection;
+
+ public DateLocaleExample() {
+ setSpacing(true);
+
+ datetime = new InlineDateField("Please select the starting time:");
+
+ // Set the value of the PopupDateField to current date
+ datetime.setValue(new java.util.Date());
+
+ // Set the correct resolution
+ datetime.setResolution(InlineDateField.RESOLUTION_MIN);
+ datetime.setImmediate(true);
+
+ // Create selection and fill it with locales
+ localeSelection = new ComboBox("Select date format:");
+ localeSelection.addListener(this);
+ localeSelection.setImmediate(true);
+ localeSelection
+ .setContainerDataSource(ExampleUtil.getLocaleContainer());
+
+ addComponent(datetime);
+ addComponent(localeSelection);
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ Item selected = localeSelection.getItem(event.getProperty().getValue());
+ datetime.setLocale((Locale) selected.getItemProperty(
+ ExampleUtil.locale_PROPERTY_LOCALE).getValue());
+ datetime.requestRepaint();
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/DatePopup.java b/src/com/vaadin/demo/sampler/features/dates/DatePopup.java
new file mode 100644
index 0000000000..fcc51cc853
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DatePopup.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.PopupDateField;
+
+public class DatePopup extends Feature {
+ @Override
+ public String getName() {
+ return "Pop-up date selection";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, the resolution is set to be one day"
+ + " and the DateField component is shown as a calendar pop-up.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(DateField.class),
+ new APIResource(PopupDateField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { DateInline.class, DateLocale.class,
+ DateResolution.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/DatePopupExample.java b/src/com/vaadin/demo/sampler/features/dates/DatePopupExample.java
new file mode 100644
index 0000000000..31e77a0e4a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DatePopupExample.java
@@ -0,0 +1,46 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.PopupDateField;
+import com.vaadin.ui.VerticalLayout;
+
+public class DatePopupExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private PopupDateField datetime;
+
+ public DatePopupExample() {
+ setSpacing(true);
+
+ datetime = new PopupDateField("Please select the starting time:");
+
+ // Set the value of the PopupDateField to current date
+ datetime.setValue(new java.util.Date());
+
+ // Set the correct resolution
+ datetime.setResolution(PopupDateField.RESOLUTION_DAY);
+
+ // Add valuechangelistener
+ datetime.addListener(this);
+ datetime.setImmediate(true);
+
+ addComponent(datetime);
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ // Get the new value and format it to the current locale
+ DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.SHORT);
+ Object value = event.getProperty().getValue();
+ if (value == null || !(value instanceof Date)) {
+ getWindow().showNotification("Invalid date entered");
+ } else {
+ String dateOut = dateFormatter.format(value);
+ // Show notification
+ getWindow().showNotification("Starting date: " + dateOut);
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/DateResolution.java b/src/com/vaadin/demo/sampler/features/dates/DateResolution.java
new file mode 100644
index 0000000000..ba3d7d112f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DateResolution.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.InlineDateField;
+
+public class DateResolution extends Feature {
+ @Override
+ public String getName() {
+ return "Date selection, resolution";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, you can select a different resolution"
+ + " from the combo box and see how the calendar component"
+ + " changes.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(DateField.class),
+ new APIResource(InlineDateField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { DateInline.class, DatePopup.class,
+ DateLocale.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/dates/DateResolutionExample.java b/src/com/vaadin/demo/sampler/features/dates/DateResolutionExample.java
new file mode 100644
index 0000000000..dbbceeb7ec
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/dates/DateResolutionExample.java
@@ -0,0 +1,69 @@
+package com.vaadin.demo.sampler.features.dates;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.VerticalLayout;
+
+public class DateResolutionExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ public static final Object resolution_PROPERTY_NAME = "name";
+ // Resolution fields from DateField
+ private static final int[] resolutions = { InlineDateField.RESOLUTION_YEAR,
+ InlineDateField.RESOLUTION_MONTH, InlineDateField.RESOLUTION_DAY,
+ InlineDateField.RESOLUTION_HOUR, InlineDateField.RESOLUTION_MIN,
+ InlineDateField.RESOLUTION_SEC, InlineDateField.RESOLUTION_MSEC };
+ private static final String[] resolutionNames = { "Year", "Month", "Day",
+ "Hour", "Minute", "Second", "Millisecond" };
+
+ private InlineDateField datetime;
+ private ComboBox localeSelection;
+
+ public DateResolutionExample() {
+ setSpacing(true);
+
+ datetime = new InlineDateField("Please select the starting time:");
+
+ // Set the value of the PopupDateField to current date
+ datetime.setValue(new java.util.Date());
+
+ // Set the correct resolution
+ datetime.setResolution(InlineDateField.RESOLUTION_DAY);
+ datetime.setImmediate(true);
+
+ // Create selection
+ localeSelection = new ComboBox("Select resolution:");
+ localeSelection.setNullSelectionAllowed(false);
+ localeSelection.addListener(this);
+ localeSelection.setImmediate(true);
+
+ // Fill the selection with choices, set captions correctly
+ localeSelection.setContainerDataSource(getResolutionContainer());
+ localeSelection.setItemCaptionPropertyId(resolution_PROPERTY_NAME);
+ localeSelection.setItemCaptionMode(ComboBox.ITEM_CAPTION_MODE_PROPERTY);
+
+ addComponent(datetime);
+ addComponent(localeSelection);
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ datetime.setResolution((Integer) event.getProperty().getValue());
+ datetime.requestRepaint();
+ }
+
+ private IndexedContainer getResolutionContainer() {
+ IndexedContainer resolutionContainer = new IndexedContainer();
+ resolutionContainer.addContainerProperty(resolution_PROPERTY_NAME,
+ String.class, null);
+ for (int i = 0; i < resolutions.length; i++) {
+ Item added = resolutionContainer.addItem(resolutions[i]);
+ added.getItemProperty(resolution_PROPERTY_NAME).setValue(
+ resolutionNames[i]);
+ }
+ return resolutionContainer;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/form/75-FormBasic.png b/src/com/vaadin/demo/sampler/features/form/75-FormBasic.png
new file mode 100644
index 0000000000..5044c729a6
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/form/75-FormBasic.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/form/75-FormPojo.png b/src/com/vaadin/demo/sampler/features/form/75-FormPojo.png
new file mode 100644
index 0000000000..df237b7cfc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/form/75-FormPojo.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/form/FormBasic.java b/src/com/vaadin/demo/sampler/features/form/FormBasic.java
new file mode 100644
index 0000000000..25bd9197d2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/form/FormBasic.java
@@ -0,0 +1,55 @@
+package com.vaadin.demo.sampler.features.form;
+
+import com.vaadin.data.Validatable;
+import com.vaadin.data.Validator;
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.commons.Errors;
+import com.vaadin.demo.sampler.features.commons.Validation;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Form;
+
+public class FormBasic extends Feature {
+
+ @Override
+ public String getName() {
+ return "Form";
+ }
+
+ @Override
+ public Component getExample() {
+ return new FormPojoExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "A Form is most useful when connected to a data source, and"
+ + " provides buffering and customization features to support"
+ + " that scenario. A Form can easily be used as a POJO"
+ + " or Bean editor by wrapping the bean using BeanItem. <br/>"
+ + "The basic functionality only requires a couple of lines of"
+ + " code, then Validators and other customizations can be "
+ + "applied to taste. <br/>Enter something and try discarding or "
+ + "applying.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Validatable.class),
+ new APIResource(Validator.class), new APIResource(Form.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { Validation.class, Errors.class,
+ FeatureSet.Forms.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/form/FormPojo.java b/src/com/vaadin/demo/sampler/features/form/FormPojo.java
new file mode 100644
index 0000000000..b2f92faa14
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/form/FormPojo.java
@@ -0,0 +1,51 @@
+package com.vaadin.demo.sampler.features.form;
+
+import com.vaadin.data.Validatable;
+import com.vaadin.data.Validator;
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.commons.Errors;
+import com.vaadin.demo.sampler.features.commons.Validation;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Form;
+
+public class FormPojo extends Feature {
+
+ @Override
+ public String getName() {
+ return "Bean-bound form";
+ }
+
+ @Override
+ public Component getExample() {
+ return new FormPojoExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "A Form can easily be used as a POJO or Bean editor by wrapping the"
+ + " bean using BeanItem. The basic functionality only requires"
+ + " a couple of lines of code, then Validators and other"
+ + " customizations can be applied to taste.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Validatable.class),
+ new APIResource(Validator.class), new APIResource(Form.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { Validation.class, Errors.class,
+ FeatureSet.Forms.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/form/FormPojoExample.java b/src/com/vaadin/demo/sampler/features/form/FormPojoExample.java
new file mode 100644
index 0000000000..e8e0ebb4b2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/form/FormPojoExample.java
@@ -0,0 +1,253 @@
+package com.vaadin.demo.sampler.features.form;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.UUID;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Validator;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.data.validator.StringLengthValidator;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.ui.BaseFieldFactory;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.Form;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+@SuppressWarnings("serial")
+public class FormPojoExample extends VerticalLayout {
+
+ // the 'POJO' we're editing
+ Person person;
+
+ public FormPojoExample() {
+
+ person = new Person(); // a person POJO
+ BeanItem personItem = new BeanItem(person); // item from POJO
+
+ // Create the Form
+ final Form personForm = new Form();
+ personForm.setWriteThrough(false); // we want explicit 'apply'
+ personForm.setInvalidCommitted(false); // no invalid values in datamodel
+
+ // FieldFactory for customizing the fields and adding validators
+ personForm.setFieldFactory(new PersonFieldFactory());
+ personForm.setItemDataSource(personItem); // bind to POJO via BeanItem
+
+ // Determines which properties are shown, and in which order:
+ personForm.setVisibleItemProperties(Arrays.asList(new String[] {
+ "firstName", "lastName", "countryCode", "password",
+ "birthdate", "shoesize", "uuid" }));
+
+ // Add form to layout
+ addComponent(personForm);
+
+ // The cancel / apply buttons
+ HorizontalLayout buttons = new HorizontalLayout();
+ buttons.setSpacing(true);
+ Button discardChanges = new Button("Discard changes",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ personForm.discard();
+ }
+ });
+ discardChanges.setStyleName(Button.STYLE_LINK);
+ buttons.addComponent(discardChanges);
+
+ Button apply = new Button("Apply", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ try {
+ personForm.commit();
+ } catch (Exception e) {
+ // Ingnored, we'll let the Form handle the errors
+ }
+ }
+ });
+ buttons.addComponent(apply);
+ personForm.getLayout().addComponent(buttons);
+
+ // button for showing the internal state of the POJO
+ Button showPojoState = new Button("Show POJO internal state",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ showPojoState();
+ }
+ });
+ addComponent(showPojoState);
+ }
+
+ private void showPojoState() {
+ Window.Notification n = new Window.Notification("POJO state",
+ Window.Notification.TYPE_TRAY_NOTIFICATION);
+ n.setPosition(Window.Notification.POSITION_CENTERED);
+ n.setDescription("First name: " + person.getFirstName()
+ + "<br/>Last name: " + person.getLastName() + "<br/>Country: "
+ + person.getCountryCode() + "<br/>Birthdate: "
+ + person.getBirthdate() + "<br/>Shoe size: "
+ + +person.getShoesize() + "<br/>Password: "
+ + person.getPassword() + "<br/>UUID: " + person.getUuid());
+ getWindow().showNotification(n);
+ }
+
+ private class PersonFieldFactory extends BaseFieldFactory {
+
+ final ComboBox countries = new ComboBox("Country");
+
+ public PersonFieldFactory() {
+ countries.setWidth("30em");
+ countries.setContainerDataSource(ExampleUtil
+ .getStaticISO3166Container());
+ countries
+ .setItemCaptionPropertyId(ExampleUtil.iso3166_PROPERTY_NAME);
+ countries.setItemIconPropertyId(ExampleUtil.iso3166_PROPERTY_FLAG);
+ countries.setFilteringMode(ComboBox.FILTERINGMODE_STARTSWITH);
+ }
+
+ @Override
+ public Field createField(Item item, Object propertyId,
+ Component uiContext) {
+ if ("countryCode".equals(propertyId)) {
+ // filtering ComboBox w/ country names
+ return countries;
+ }
+ Field f = super.createField(item, propertyId, uiContext);
+ if ("firstName".equals(propertyId)) {
+ TextField tf = (TextField) f;
+ tf.setRequired(true);
+ tf.setRequiredError("Please enter a First Name");
+ tf.setWidth("15em");
+ tf.addValidator(new StringLengthValidator(
+ "First Name must be 3-25 characters", 3, 25, false));
+ } else if ("lastName".equals(propertyId)) {
+ TextField tf = (TextField) f;
+ tf.setRequired(true);
+ tf.setRequiredError("Please enter a Last Name");
+ tf.setWidth("20em");
+ tf.addValidator(new StringLengthValidator(
+ "Last Name must be 3-50 characters", 3, 50, false));
+ } else if ("password".equals(propertyId)) {
+ TextField tf = (TextField) f;
+ tf.setSecret(true);
+ tf.setRequired(true);
+ tf.setRequiredError("Please enter a password");
+ tf.setWidth("10em");
+ tf.addValidator(new StringLengthValidator(
+ "Password must be 6-20 characters", 6, 20, false));
+ } else if ("shoesize".equals(propertyId)) {
+ TextField tf = (TextField) f;
+ tf.addValidator(new IntegerValidator(
+ "Shoe size must be an Integer"));
+ tf.setWidth("2em");
+ } else if ("uuid".equals(propertyId)) {
+ TextField tf = (TextField) f;
+ tf.setWidth("20em");
+ }
+
+ return f;
+ }
+ }
+
+ public class Person implements Serializable {
+
+ private String firstName = "";
+ private String lastName = "";
+ private Date birthdate;
+ private int shoesize = 42;
+ private String password = "";
+ private UUID uuid;
+ private String countryCode = "";
+
+ public Person() {
+ uuid = UUID.randomUUID();
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public Date getBirthdate() {
+ return birthdate;
+ }
+
+ public void setBirthdate(Date birthdate) {
+ this.birthdate = birthdate;
+ }
+
+ public int getShoesize() {
+ return shoesize;
+ }
+
+ public void setShoesize(int shoesize) {
+ this.shoesize = shoesize;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public String getCountryCode() {
+ return countryCode;
+ }
+
+ public void setCountryCode(String countryCode) {
+ this.countryCode = countryCode;
+ }
+
+ }
+
+ public class IntegerValidator implements Validator {
+
+ private String message;
+
+ public IntegerValidator(String message) {
+ this.message = message;
+ }
+
+ public boolean isValid(Object value) {
+ if (value == null || !(value instanceof String)) {
+ return false;
+ }
+ try {
+ Integer.parseInt((String) value);
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ public void validate(Object value) throws InvalidValueException {
+ if (!isValid(value)) {
+ throw new InvalidValueException(message);
+ }
+ }
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-ApplicationLayout.png b/src/com/vaadin/demo/sampler/features/layouts/75-ApplicationLayout.png
new file mode 100644
index 0000000000..ee1d0a1c78
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-ApplicationLayout.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-CustomLayouts.png b/src/com/vaadin/demo/sampler/features/layouts/75-CustomLayouts.png
new file mode 100644
index 0000000000..a37e342d9e
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-CustomLayouts.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-ExpandingComponent.png b/src/com/vaadin/demo/sampler/features/layouts/75-ExpandingComponent.png
new file mode 100644
index 0000000000..dcc9ac5550
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-ExpandingComponent.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-GridLayoutBasic.png b/src/com/vaadin/demo/sampler/features/layouts/75-GridLayoutBasic.png
new file mode 100644
index 0000000000..a9c298cf3f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-GridLayoutBasic.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-HorizontalLayoutBasic.png b/src/com/vaadin/demo/sampler/features/layouts/75-HorizontalLayoutBasic.png
new file mode 100644
index 0000000000..d83a7183d5
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-HorizontalLayoutBasic.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-LayoutAlignment.png b/src/com/vaadin/demo/sampler/features/layouts/75-LayoutAlignment.png
new file mode 100644
index 0000000000..3aedc76879
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-LayoutAlignment.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-LayoutMargin.png b/src/com/vaadin/demo/sampler/features/layouts/75-LayoutMargin.png
new file mode 100644
index 0000000000..802ef00a86
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-LayoutMargin.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-LayoutSpacing.png b/src/com/vaadin/demo/sampler/features/layouts/75-LayoutSpacing.png
new file mode 100644
index 0000000000..502bdc169b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-LayoutSpacing.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-SplitPanelBasic.png b/src/com/vaadin/demo/sampler/features/layouts/75-SplitPanelBasic.png
new file mode 100644
index 0000000000..562d6af32b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-SplitPanelBasic.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-VerticalLayoutBasic.png b/src/com/vaadin/demo/sampler/features/layouts/75-VerticalLayoutBasic.png
new file mode 100644
index 0000000000..2e6bf6b484
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-VerticalLayoutBasic.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/75-WebLayout.png b/src/com/vaadin/demo/sampler/features/layouts/75-WebLayout.png
new file mode 100644
index 0000000000..a9405c768c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/75-WebLayout.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/layouts/ApplicationLayout.java b/src/com/vaadin/demo/sampler/features/layouts/ApplicationLayout.java
new file mode 100644
index 0000000000..38194b4c64
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/ApplicationLayout.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class ApplicationLayout extends Feature {
+
+ @Override
+ public String getName() {
+ return "Application-style layout";
+ }
+
+ @Override
+ public String getDescription() {
+ return "It can be helpful to distinguish between <i>web-style</i> and"
+ + " <i>application-style</i> layouting (although this is a"
+ + " simplification). Both styles are supported, and can be used"
+ + " simultaneously.<br/> Application-style layouting uses relatively"
+ + " -sized components, growing dynamically with the window, and"
+ + " causing scrollbars to appear on well-defined areas within the"
+ + " window."
+ + "<br/>Try resizing the window to see how the content reacts.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(HorizontalLayout.class),
+ new APIResource(VerticalLayout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { WebLayout.class, CustomLayouts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/ApplicationLayoutExample.java b/src/com/vaadin/demo/sampler/features/layouts/ApplicationLayoutExample.java
new file mode 100644
index 0000000000..79b6e1258f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/ApplicationLayoutExample.java
@@ -0,0 +1,99 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import java.util.Iterator;
+
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Window.CloseEvent;
+
+public class ApplicationLayoutExample extends VerticalLayout {
+
+ Window win = new ApplicationLayoutWindow();
+ Button open = new Button("Open sample in subwindow");
+
+ public ApplicationLayoutExample() {
+ setMargin(true);
+
+ // We'll open this example in a separate window, configure it
+ win.setWidth("70%");
+ win.setHeight("70%");
+ win.center();
+ // Allow opening window again when closed
+ win.addListener(new Window.CloseListener() {
+ public void windowClose(CloseEvent e) {
+ open.setEnabled(true);
+ }
+ });
+
+ // 'open sample' button
+ addComponent(open);
+ open.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ getWindow().addWindow(win);
+ open.setEnabled(false);
+ }
+ });
+ addComponent(new Label(
+ ("Don't worry: the content of the window is not supposed to make sense...")));
+
+ }
+
+ class ApplicationLayoutWindow extends Window {
+ ApplicationLayoutWindow() {
+ // Our main layout is a horizontal layout
+ HorizontalLayout main = new HorizontalLayout();
+ main.setSizeFull();
+ setLayout(main);
+
+ // Tree to the left
+ Panel treePanel = new Panel(); // for scrollbars
+ treePanel.setStyleName(Panel.STYLE_LIGHT);
+ treePanel.setHeight("100%");
+ treePanel.setWidth(null);
+ treePanel.getLayout().setSizeUndefined();
+ addComponent(treePanel);
+
+ Tree tree = new Tree();
+ tree.setContainerDataSource(ExampleUtil.getHardwareContainer());
+ tree.setItemCaptionPropertyId(ExampleUtil.hw_PROPERTY_NAME);
+ for (Iterator it = tree.rootItemIds().iterator(); it.hasNext();) {
+ tree.expandItemsRecursively(it.next());
+ }
+ treePanel.addComponent(tree);
+
+ // vertically divide the right area
+ VerticalLayout left = new VerticalLayout();
+ left.setSizeFull();
+ addComponent(left);
+ main.setExpandRatio(left, 1.0f); // use all available space
+
+ // table on top
+ Table tbl = new Table();
+ tbl.setWidth("100%");
+ tbl.setContainerDataSource(ExampleUtil.getISO3166Container());
+ tbl.setSortDisabled(true);
+ tbl.setPageLength(7);
+ left.addComponent(tbl);
+
+ // Label on bottom
+ Panel textPanel = new Panel(); // for scrollbars
+ textPanel.setStyleName(Panel.STYLE_LIGHT);
+ textPanel.setSizeFull();
+ left.addComponent(textPanel);
+ left.setExpandRatio(textPanel, 1.0f); // use all available space
+
+ Label text = new Label(ExampleUtil.lorem, Label.CONTENT_XHTML);
+ text.setWidth("500px"); // some limit is good for text
+ textPanel.addComponent(text);
+
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/layouts/CustomLayouts.java b/src/com/vaadin/demo/sampler/features/layouts/CustomLayouts.java
new file mode 100644
index 0000000000..8ade132ac2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/CustomLayouts.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.CustomLayout;
+
+public class CustomLayouts extends Feature {
+
+ @Override
+ public String getName() {
+ return "Custom layout";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The CustomLayout allows you to make a layout in regular HTML,"
+ + " using styles and embedding images to suit your needs."
+ + " You can even make the layout using a WYSIWYG editor.<br/>"
+ + " Marking an area in the HTML as a named <i>location</i>"
+ + " will allow you to replace that area with a component later."
+ + "<br/>HTML prototypes can often be quickly converted into a"
+ + " working application this way, providing a clear path from"
+ + " design to implementation.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(CustomLayout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { WebLayout.class, ApplicationLayout.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "Layout HTML (view source)", getThemeBase()
+ + "layouts/examplecustomlayout.html") };
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/CustomLayoutsExample.java b/src/com/vaadin/demo/sampler/features/layouts/CustomLayoutsExample.java
new file mode 100644
index 0000000000..f829009555
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/CustomLayoutsExample.java
@@ -0,0 +1,30 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CustomLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class CustomLayoutsExample extends VerticalLayout {
+
+ public CustomLayoutsExample() {
+ setMargin(true);
+
+ // Create the custom layout and set it as a component in
+ // the current layout
+ CustomLayout custom = new CustomLayout("examplecustomlayout");
+ addComponent(custom);
+
+ // Create components and bind them to the location tags
+ // in the custom layout.
+ TextField username = new TextField();
+ custom.addComponent(username, "username");
+
+ TextField password = new TextField();
+ password.setSecret(true);
+ custom.addComponent(password, "password");
+
+ Button ok = new Button("Login");
+ custom.addComponent(ok, "okbutton");
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/layouts/ExpandingComponent.java b/src/com/vaadin/demo/sampler/features/layouts/ExpandingComponent.java
new file mode 100644
index 0000000000..8a58d73eb7
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/ExpandingComponent.java
@@ -0,0 +1,41 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.HorizontalLayout;
+
+public class ExpandingComponent extends Feature {
+
+ @Override
+ public String getName() {
+ return "Expanding components";
+ }
+
+ @Override
+ public String getDescription() {
+ return "You can <i>expand</i> components to make them"
+ + " occupy the space left over by other components.<br/>"
+ + " If more than one component is expanded, the <i>ratio</i>"
+ + " determines how the leftover space is shared between the"
+ + " expanded components.<br/>Mousover each component for a"
+ + " description (tooltip).<br/> Also try resizing the window.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(HorizontalLayout.class),
+
+ };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] {};
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/ExpandingComponentExample.java b/src/com/vaadin/demo/sampler/features/layouts/ExpandingComponentExample.java
new file mode 100644
index 0000000000..1638fbe8a2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/ExpandingComponentExample.java
@@ -0,0 +1,64 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class ExpandingComponentExample extends VerticalLayout {
+
+ public ExpandingComponentExample() {
+ setSpacing(true);
+
+ { // Basic scenario: single expanded component
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.setWidth("100%"); // make the layout grow with the window
+ // size
+ addComponent(layout);
+
+ Button naturalButton = new Button("Natural");
+ naturalButton
+ .setDescription("This button does not have an explicit size - instead, it's size depends on it's content - a.k.a <i>natural size.</i>");
+ layout.addComponent(naturalButton);
+
+ Button expandedButton = new Button("Expanded");
+ expandedButton.setWidth("100%");
+ expandedButton
+ .setDescription("This button is set to 100% and expanded, and will thus occupy the space left over by the other components.");
+ layout.addComponent(expandedButton);
+ layout.setExpandRatio(expandedButton, 1.0f);
+
+ Button sizedButton = new Button("Explicit");
+ sizedButton.setWidth("150px");
+ sizedButton
+ .setDescription("This button is explicitly set to be 150 pixels wide.");
+ layout.addComponent(sizedButton);
+ }
+
+ { // Ratio example
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.setWidth("100%"); // make the layout grow with the window
+ // size
+ addComponent(layout);
+
+ Button naturalButton = new Button("Natural");
+ naturalButton
+ .setDescription("This button does not have an explicit size - instead, it's size depends on it's content - a.k.a <i>natural size.</i>");
+ layout.addComponent(naturalButton);
+
+ Button expandedButton1 = new Button("Ratio 1.0");
+ expandedButton1.setWidth("100%");
+ expandedButton1
+ .setDescription("This button is set to 100% and expanded with a ratio of 1.0, and will in this example occupy 1:2 of the leftover space.");
+ layout.addComponent(expandedButton1);
+ layout.setExpandRatio(expandedButton1, 1.0f);
+
+ Button expandedButton2 = new Button("Ratio 2.0");
+ expandedButton2.setWidth("100%");
+ expandedButton2
+ .setDescription("This button is set to 100% and expanded with a ratio of 2.0, and will in this example occupy 2:1 of the leftover space.");
+ layout.addComponent(expandedButton2);
+ layout.setExpandRatio(expandedButton2, 2.0f);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasic.java b/src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasic.java
new file mode 100644
index 0000000000..e850e5ab4c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasic.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.GridLayout;
+
+public class GridLayoutBasic extends Feature {
+
+ @Override
+ public String getName() {
+ return "Grid layout";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The GridLayout allows you to create a grid of components."
+ + " The grid may have an arbitrary number of cells in each direction"
+ + " and you can easily set components to fill multiple cells.<br/>It supports all basic features, plus some advanced stuff - including spacing, margin, alignment, and expand ratios.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(GridLayout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { HorizontalLayoutBasic.class,
+ VerticalLayoutBasic.class, LayoutSpacing.class,
+ LayoutMargin.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "CSS for the layout", getThemeBase()
+ + "layouts/gridexample.css") };
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasicExample.java b/src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasicExample.java
new file mode 100644
index 0000000000..6b5e430664
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/GridLayoutBasicExample.java
@@ -0,0 +1,55 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.terminal.Sizeable;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class GridLayoutBasicExample extends VerticalLayout {
+
+ public GridLayoutBasicExample() {
+ // Create a grid layout
+ final GridLayout grid = new GridLayout(3, 3);
+ grid.setSpacing(true);
+
+ // The style allows us to visualize the cell borders in this example.
+ grid.addStyleName("gridexample");
+
+ grid.setWidth(400, Sizeable.UNITS_PIXELS);
+ grid.setHeight(400, Sizeable.UNITS_PIXELS);
+
+ // First we insert four components that occupy one cell each
+ Button topleft = new Button("Top Left");
+ grid.addComponent(topleft, 0, 0);
+ grid.setComponentAlignment(topleft, Alignment.MIDDLE_CENTER);
+
+ Button topcenter = new Button("Top Center");
+ grid.addComponent(topcenter, 1, 0);
+ grid.setComponentAlignment(topcenter, Alignment.MIDDLE_CENTER);
+
+ Button bottomleft = new Button("Bottom Left");
+ grid.addComponent(bottomleft, 0, 2);
+ grid.setComponentAlignment(bottomleft, Alignment.MIDDLE_CENTER);
+
+ Button bottomcenter = new Button("Bottom Center");
+ grid.addComponent(bottomcenter, 1, 2);
+ grid.setComponentAlignment(bottomcenter, Alignment.MIDDLE_CENTER);
+
+ // Insert a component that occupies all the rightmost cells
+ Button topright = new Button("Extra height");
+ grid.addComponent(topright, 2, 0, 2, 2);
+ grid.setComponentAlignment(topright, Alignment.MIDDLE_CENTER);
+
+ // Insert a component that occupies two cells in horizontal direction
+ Button middleleft = new Button("This is a wide cell in GridLayout");
+ grid.addComponent(middleleft, 0, 1, 1, 1);
+ grid.setComponentAlignment(middleleft, Alignment.MIDDLE_CENTER);
+
+ // Add the layout to the containing layout.
+ addComponent(grid);
+
+ // Align the grid itself within its container layout.
+ setComponentAlignment(grid, Alignment.MIDDLE_CENTER);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasic.java b/src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasic.java
new file mode 100644
index 0000000000..3c72b2733f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasic.java
@@ -0,0 +1,35 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.HorizontalLayout;
+
+public class HorizontalLayoutBasic extends Feature {
+
+ @Override
+ public String getName() {
+ return "Horizontal layout";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The HorizontalLayout arranges components horizontally.<br/>It supports all basic features, plus some advanced stuff - including spacing, margin, alignment, and expand ratios.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(HorizontalLayout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { VerticalLayoutBasic.class, LayoutSpacing.class,
+ LayoutAlignment.class, };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasicExample.java b/src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasicExample.java
new file mode 100644
index 0000000000..4b09f218bc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/HorizontalLayoutBasicExample.java
@@ -0,0 +1,48 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+
+public class HorizontalLayoutBasicExample extends HorizontalLayout {
+
+ public HorizontalLayoutBasicExample() {
+ // this is a HorizontalLayout
+
+ // First TextField
+ TextField tf = new TextField();
+ tf.setWidth("70px");
+ addComponent(tf);
+
+ // A dash
+ Label dash = new Label("-");
+ addComponent(dash);
+ setComponentAlignment(dash, "middle");
+
+ // Second TextField
+ tf = new TextField();
+ tf.setWidth("70px");
+ addComponent(tf);
+
+ // Another dash
+ dash = new Label("-");
+ addComponent(dash);
+ setComponentAlignment(dash, "middle");
+
+ // Third TextField
+ tf = new TextField();
+ tf.setWidth("70px");
+ addComponent(tf);
+
+ // Yet another dash
+ dash = new Label("-");
+ addComponent(dash);
+ setComponentAlignment(dash, "middle");
+
+ // Forth and last TextField
+ tf = new TextField();
+ tf.setWidth("70px");
+ addComponent(tf);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/LayoutAlignment.java b/src/com/vaadin/demo/sampler/features/layouts/LayoutAlignment.java
new file mode 100644
index 0000000000..531ae1acdc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/LayoutAlignment.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class LayoutAlignment extends Feature {
+
+ @Override
+ public String getName() {
+ return "Component Alignment";
+ }
+
+ @Override
+ public String getDescription() {
+ return "GridLayout, VerticalLayout, and HorizontalLayout, "
+ + "which are tabular layouts consisting of cells, "
+ + "support alignment of components within the layout cells. "
+ + "The alignment of a component within its respective cell "
+ + "is set with setComponentAlignment().";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(VerticalLayout.class),
+ new APIResource(HorizontalLayout.class),
+ new APIResource(GridLayout.class), };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { HorizontalLayoutBasic.class,
+ VerticalLayoutBasic.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/LayoutAlignmentExample.java b/src/com/vaadin/demo/sampler/features/layouts/LayoutAlignmentExample.java
new file mode 100644
index 0000000000..853aedd003
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/LayoutAlignmentExample.java
@@ -0,0 +1,88 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.terminal.gwt.client.ui.AlignmentInfo.Bits;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class LayoutAlignmentExample extends VerticalLayout {
+
+ @SuppressWarnings("deprecation")
+ public LayoutAlignmentExample() {
+ // Create a grid layout
+ final GridLayout grid = new GridLayout(1, 9);
+ grid.setSpacing(true);
+
+ // The style allows us to visualize the cell borders in this example.
+ grid.addStyleName("gridexample");
+
+ grid.setWidth("300px");
+ grid.setHeight("500px");
+
+ // Put a component in each cell with respective alignment.
+ // We'll use different ways to set the alignment: constants, bitmasks,
+ // and string-shorthand.
+
+ // Here we use the shorthand constants to set the alignment:
+ // Alignment.TOP_LEFT, Alignment.TOP_CENTER, Alignment.TOP_RIGHT
+ // Alignment.MIDDLE_LEFT, Alignment.MIDDLE_CENTER,
+ // Alignment.MIDDLE_RIGHT
+ // Alignment.BOTTOM_LEFT, Alignment.BOTTOM_CENTER,
+ // Alignment.BOTTOM_RIGHT
+
+ Button topleft = new Button("Top Left");
+ grid.addComponent(topleft);
+ grid.setComponentAlignment(topleft, Alignment.TOP_LEFT);
+
+ Button topcenter = new Button("Top Center");
+ grid.addComponent(topcenter);
+ grid.setComponentAlignment(topcenter, Alignment.TOP_CENTER);
+
+ Button topright = new Button("Top Right");
+ grid.addComponent(topright);
+ grid.setComponentAlignment(topright, Alignment.TOP_RIGHT);
+
+ // Here we use bit additions to set the alignment:
+ // Bits.ALIGNMENT_LEFT, Bits.ALIGNMENT_RIGHT
+ // Bits.ALIGNMENT_TOP, Bits.ALIGNMENT_BOTTOM
+ // Bits.ALIGNMENT_VERTICAL_CENTER, Bits.ALIGNMENT_HORIZONTAL_CENTER
+
+ Button middleleft = new Button("Middle Left");
+ grid.addComponent(middleleft);
+ grid.setComponentAlignment(middleleft, new Alignment(
+ Bits.ALIGNMENT_VERTICAL_CENTER | Bits.ALIGNMENT_LEFT));
+
+ Button middlecenter = new Button("Middle Center");
+ grid.addComponent(middlecenter);
+ grid.setComponentAlignment(middlecenter, new Alignment(
+ Bits.ALIGNMENT_VERTICAL_CENTER
+ | Bits.ALIGNMENT_HORIZONTAL_CENTER));
+
+ Button middleright = new Button("Middle Right");
+ grid.addComponent(middleright);
+ grid.setComponentAlignment(middleright, new Alignment(
+ Bits.ALIGNMENT_VERTICAL_CENTER | Bits.ALIGNMENT_RIGHT));
+
+ // Here we'll use the convenient string-shorthand:
+
+ Button bottomleft = new Button("Bottom Left");
+ grid.addComponent(bottomleft);
+ grid.setComponentAlignment(bottomleft, "bottom left");
+
+ Button bottomcenter = new Button("Bottom Center");
+ grid.addComponent(bottomcenter);
+ grid.setComponentAlignment(bottomcenter, "bottom center");
+
+ Button bottomright = new Button("Bottom Right");
+ grid.addComponent(bottomright);
+ grid.setComponentAlignment(bottomright, "bottom right");
+
+ // Add the layout to the containing layout.
+ addComponent(grid);
+
+ // Align the grid itself within its container layout.
+ setComponentAlignment(grid, Alignment.MIDDLE_CENTER);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/LayoutMargin.java b/src/com/vaadin/demo/sampler/features/layouts/LayoutMargin.java
new file mode 100644
index 0000000000..e2c88434d9
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/LayoutMargin.java
@@ -0,0 +1,47 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class LayoutMargin extends Feature {
+
+ @Override
+ public String getName() {
+ return "Layout margin";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Layouts can have margins on any of the sides. The actual size"
+ + " of the margin is determined by the theme, and can be"
+ + " customized using CSS - in this example, the right margin"
+ + " size is increased.<br/>Note that <i>margin</i>"
+ + " is the space around the layout as a whole, and"
+ + " <i>spacing</i> is the space between the component within"
+ + " the layout.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(VerticalLayout.class),
+ new APIResource(HorizontalLayout.class),
+ new APIResource(GridLayout.class), };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LayoutSpacing.class, HorizontalLayoutBasic.class,
+ VerticalLayoutBasic.class, GridLayoutBasic.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "CSS for the layout", getThemeBase()
+ + "layouts/marginexample.css") };
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/LayoutMarginExample.java b/src/com/vaadin/demo/sampler/features/layouts/LayoutMarginExample.java
new file mode 100644
index 0000000000..355486db79
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/LayoutMarginExample.java
@@ -0,0 +1,58 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class LayoutMarginExample extends GridLayout implements
+ Button.ClickListener {
+
+ VerticalLayout marginLayout;
+ Button topMargin;
+ Button rightMargin;
+ Button bottomMargin;
+ Button leftMargin;
+
+ public LayoutMarginExample() {
+ super(3, 3);
+
+ space();
+ topMargin = new Button("Top margin", this);
+ topMargin.setSwitchMode(true);
+ addComponent(topMargin);
+ setComponentAlignment(topMargin, "center");
+
+ space();
+ leftMargin = new Button("Left margin", this);
+ leftMargin.setSwitchMode(true);
+ addComponent(leftMargin);
+ setComponentAlignment(leftMargin, "middle");
+
+ marginLayout = new VerticalLayout();
+ marginLayout.setStyleName("marginexample");
+ marginLayout.setSizeUndefined();
+ addComponent(marginLayout);
+ marginLayout.addComponent(new Label("Margins all around?"));
+
+ rightMargin = new Button("Right margin", this);
+ rightMargin.setSwitchMode(true);
+ addComponent(rightMargin);
+ setComponentAlignment(rightMargin, "middle");
+
+ space();
+ bottomMargin = new Button("Bottom margin", this);
+ bottomMargin.setSwitchMode(true);
+ addComponent(bottomMargin);
+ setComponentAlignment(bottomMargin, "center");
+
+ }
+
+ public void buttonClick(ClickEvent event) {
+ marginLayout.setMargin(topMargin.booleanValue(), rightMargin
+ .booleanValue(), bottomMargin.booleanValue(), leftMargin
+ .booleanValue());
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/LayoutSpacing.java b/src/com/vaadin/demo/sampler/features/layouts/LayoutSpacing.java
new file mode 100644
index 0000000000..b6d214289e
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/LayoutSpacing.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class LayoutSpacing extends Feature {
+
+ @Override
+ public String getName() {
+ return "Layout Spacing";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Spacing between components can be enabled or disabled."
+ + " The actual size of the spacing is determined by the theme,"
+ + " and can be customized with CSS.<br/>Note that <i>spacing</i>"
+ + " is the space between components within the layout, and"
+ + " <i>margin</i> is the space around the layout as a whole.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(VerticalLayout.class),
+ new APIResource(HorizontalLayout.class),
+ new APIResource(GridLayout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LayoutMargin.class, HorizontalLayoutBasic.class,
+ VerticalLayoutBasic.class, GridLayoutBasic.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/LayoutSpacingExample.java b/src/com/vaadin/demo/sampler/features/layouts/LayoutSpacingExample.java
new file mode 100644
index 0000000000..62891ac77d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/LayoutSpacingExample.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class LayoutSpacingExample extends VerticalLayout {
+
+ public LayoutSpacingExample() {
+ // Create a grid layout.
+ final GridLayout grid = new GridLayout(3, 3);
+
+ // Add the layout to the containing layout.
+ addComponent(grid);
+
+ // Add a style to allow customization of the layout.
+ grid.addStyleName("spacingexample");
+
+ // Populate the layout with components.
+ for (int i = 0; i < 9; i++) {
+ grid.addComponent(new Button("Component " + (i + 1)));
+ }
+
+ // CheckBox for toggling spacing on and off
+ final CheckBox spacing = new CheckBox("Spacing enabled");
+ spacing.setImmediate(true);
+ spacing.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ grid.setSpacing(spacing.booleanValue());
+ }
+ });
+ addComponent(spacing);
+
+ setSpacing(true); // enable spacing for the example itself
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasic.java b/src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasic.java
new file mode 100644
index 0000000000..3ac9fe606e
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasic.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.SplitPanel;
+
+public class SplitPanelBasic extends Feature {
+
+ @Override
+ public String getName() {
+ return "Split panel";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The SplitPanel has two resizable component areas, either"
+ + " vertically or horizontally oriented. The split position"
+ + " can optionally be locked.<br/> By nesting split panels,"
+ + " one can make quite complicated, dynamic layouts.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(SplitPanel.class),
+
+ };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] {};
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasicExample.java b/src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasicExample.java
new file mode 100644
index 0000000000..b1dd1972ab
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/SplitPanelBasicExample.java
@@ -0,0 +1,50 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.SplitPanel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SplitPanelBasicExample extends VerticalLayout {
+
+ public static final String brownFox = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. ";
+
+ public SplitPanelBasicExample() {
+ // First a vertical SplitPanel
+ final SplitPanel vert = new SplitPanel();
+ vert.setHeight("450px");
+ vert.setWidth("100%");
+ // vert.setOrientation(SplitPanel.ORIENTATION_VERTICAL); // default
+ vert.setSplitPosition(150, SplitPanel.UNITS_PIXELS);
+ addComponent(vert);
+
+ // add a label to the upper area
+ vert.addComponent(new Label(brownFox));
+
+ // Add a horizontal SplitPanel to the lower area
+ final SplitPanel horiz = new SplitPanel();
+ horiz.setOrientation(SplitPanel.ORIENTATION_HORIZONTAL);
+ horiz.setSplitPosition(50); // percent
+ vert.addComponent(horiz);
+
+ // left component:
+ horiz.addComponent(new Label(brownFox));
+
+ // right component:
+ horiz.addComponent(new Label(brownFox));
+
+ // Lock toggle button
+ Button toggleLocked = new Button("Splits locked",
+ new Button.ClickListener() {
+ // inline click.listener
+ public void buttonClick(ClickEvent event) {
+ vert.setLocked(event.getButton().booleanValue());
+ horiz.setLocked(event.getButton().booleanValue());
+ }
+ });
+ toggleLocked.setSwitchMode(true);
+ addComponent(toggleLocked);
+
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasic.java b/src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasic.java
new file mode 100644
index 0000000000..64a085abda
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasic.java
@@ -0,0 +1,37 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.VerticalLayout;
+
+public class VerticalLayoutBasic extends Feature {
+
+ @Override
+ public String getName() {
+ return "Vertical layout";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The VerticalLayout arranges components vertically. "
+ + " It is 100% wide by default, which is nice in many cases,"
+ + " but something to be aware of if trouble arises.<br/>It supports all basic features, plus some advanced stuff - including spacing, margin, alignment, and expand ratios.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(VerticalLayout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { HorizontalLayoutBasic.class, LayoutSpacing.class,
+ LayoutAlignment.class, };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasicExample.java b/src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasicExample.java
new file mode 100644
index 0000000000..7881f325c2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/VerticalLayoutBasicExample.java
@@ -0,0 +1,18 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class VerticalLayoutBasicExample extends VerticalLayout {
+
+ public VerticalLayoutBasicExample() {
+ // this is a VerticalLayout
+ // let's add some components
+ for (int i = 0; i < 5; i++) {
+ TextField tf = new TextField("Row " + (i + 1));
+ tf.setWidth("300px");
+ // Add the component to the VerticalLayout
+ addComponent(tf);
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/WebLayout.java b/src/com/vaadin/demo/sampler/features/layouts/WebLayout.java
new file mode 100644
index 0000000000..6edad21e4f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/WebLayout.java
@@ -0,0 +1,44 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class WebLayout extends Feature {
+
+ @Override
+ public String getName() {
+ return "Web-style layout";
+ }
+
+ @Override
+ public String getDescription() {
+ return "It can be helpful to distinguish between <i>web-style</i> and"
+ + " <i>application-style</i> layouting (although this is a"
+ + " simplification). Both styles are supported, and can be used"
+ + " simultaneously.<br/> Web-style layouting allows the content"
+ + " to dictate the size of the components by \"pushing\" the"
+ + " size, causing scrollbars to appear for the whole window"
+ + " when needed. This can be achieved by not setting the size"
+ + " for components, or setting an absolute size (e.g 200px)."
+ + "<br/>Try resizing the window to see how the content reacts.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(HorizontalLayout.class),
+ new APIResource(VerticalLayout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ApplicationLayout.class, CustomLayouts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/layouts/WebLayoutExample.java b/src/com/vaadin/demo/sampler/features/layouts/WebLayoutExample.java
new file mode 100644
index 0000000000..a0fe32df5d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/layouts/WebLayoutExample.java
@@ -0,0 +1,87 @@
+package com.vaadin.demo.sampler.features.layouts;
+
+import java.util.Iterator;
+
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Window.CloseEvent;
+
+public class WebLayoutExample extends VerticalLayout {
+
+ Window win = new WebLayoutWindow();
+ Button open = new Button("Open sample in subwindow");
+
+ public WebLayoutExample() {
+ setMargin(true);
+
+ // We'll open this example in a separate window, configure it
+ win.setWidth("70%");
+ win.setHeight("70%");
+ win.center();
+ // Allow opening window again when closed
+ win.addListener(new Window.CloseListener() {
+ public void windowClose(CloseEvent e) {
+ open.setEnabled(true);
+ }
+ });
+
+ // 'open sample' button
+ addComponent(open);
+ open.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ getWindow().addWindow(win);
+ open.setEnabled(false);
+ }
+ });
+
+ addComponent(new Label(
+ ("Don't worry: the content of the window is not supposed to make sense...")));
+
+ }
+
+ class WebLayoutWindow extends Window {
+ WebLayoutWindow() {
+ // Our main layout is a horiozontal layout
+ HorizontalLayout main = new HorizontalLayout();
+ main.setMargin(true);
+ main.setSpacing(true);
+ setLayout(main);
+
+ // Tree to the left
+ Tree tree = new Tree();
+ tree.setContainerDataSource(ExampleUtil.getHardwareContainer());
+ tree.setItemCaptionPropertyId(ExampleUtil.hw_PROPERTY_NAME);
+ for (Iterator it = tree.rootItemIds().iterator(); it.hasNext();) {
+ tree.expandItemsRecursively(it.next());
+ }
+ addComponent(tree);
+
+ // vertically divide the right area
+ VerticalLayout left = new VerticalLayout();
+ left.setSpacing(true);
+ addComponent(left);
+
+ // table on top
+ Table tbl = new Table();
+ tbl.setWidth("500px");
+ tbl.setContainerDataSource(ExampleUtil.getISO3166Container());
+ tbl.setSortDisabled(true);
+ tbl.setPageLength(7);
+ left.addComponent(tbl);
+
+ // Label on bottom
+ Label text = new Label(ExampleUtil.lorem, Label.CONTENT_XHTML);
+ text.setWidth("500px"); // some limit is good for text
+ left.addComponent(text);
+
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/link/75-LinkCurrentWindow.png b/src/com/vaadin/demo/sampler/features/link/75-LinkCurrentWindow.png
new file mode 100644
index 0000000000..c9bcfd729e
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/75-LinkCurrentWindow.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/link/75-LinkNoDecorations.png b/src/com/vaadin/demo/sampler/features/link/75-LinkNoDecorations.png
new file mode 100644
index 0000000000..6ec2449a59
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/75-LinkNoDecorations.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/link/75-LinkSizedWindow.png b/src/com/vaadin/demo/sampler/features/link/75-LinkSizedWindow.png
new file mode 100644
index 0000000000..46333cd88d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/75-LinkSizedWindow.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/link/LinkCurrentWindow.java b/src/com/vaadin/demo/sampler/features/link/LinkCurrentWindow.java
new file mode 100644
index 0000000000..4880f42d0b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/LinkCurrentWindow.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.sampler.features.link;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.buttons.ButtonLink;
+import com.vaadin.ui.Link;
+
+public class LinkCurrentWindow extends Feature {
+
+ @Override
+ public String getName() {
+ return "Link";
+ }
+
+ @Override
+ public String getDescription() {
+ return "By default, links open in the current browser window (use the browser back-button to get back).";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Link.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LinkNoDecorations.class, LinkSizedWindow.class,
+ ButtonLink.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/link/LinkCurrentWindowExample.java b/src/com/vaadin/demo/sampler/features/link/LinkCurrentWindowExample.java
new file mode 100644
index 0000000000..153f572258
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/LinkCurrentWindowExample.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.sampler.features.link;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.VerticalLayout;
+
+public class LinkCurrentWindowExample extends VerticalLayout {
+
+ private static final String CAPTION = "Open Google";
+ private static final String TOOLTIP = "http://www.google.com";
+ private static final ThemeResource ICON = new ThemeResource(
+ "icons/icon_world.gif");
+
+ public LinkCurrentWindowExample() {
+ setSpacing(true);
+
+ // Link w/ text and tooltip
+ Link l = new Link(CAPTION,
+ new ExternalResource("http://www.google.com"));
+ l.setDescription(TOOLTIP);
+ addComponent(l);
+
+ // Link w/ text, icon and tooltip
+ l = new Link(CAPTION, new ExternalResource("http://www.google.com"));
+ l.setDescription(TOOLTIP);
+ l.setIcon(ICON);
+ addComponent(l);
+
+ // Link w/ icon and tooltip
+ l = new Link();
+ l.setResource(new ExternalResource("http://www.google.com"));
+ l.setDescription(TOOLTIP);
+ l.setIcon(ICON);
+ addComponent(l);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/link/LinkNoDecorations.java b/src/com/vaadin/demo/sampler/features/link/LinkNoDecorations.java
new file mode 100644
index 0000000000..7f20dc65c8
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/LinkNoDecorations.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.sampler.features.link;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.buttons.ButtonLink;
+import com.vaadin.ui.Link;
+
+public class LinkNoDecorations extends Feature {
+
+ @Override
+ public String getName() {
+ return "Link, configure window";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Links can open new browser windows, and configure the amount of browser features shown, such as toolbar and addressbar.<br/>These links open a browser window without decorations.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Link.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LinkCurrentWindow.class, LinkSizedWindow.class,
+ ButtonLink.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/link/LinkNoDecorationsExample.java b/src/com/vaadin/demo/sampler/features/link/LinkNoDecorationsExample.java
new file mode 100644
index 0000000000..65ac59f12d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/LinkNoDecorationsExample.java
@@ -0,0 +1,44 @@
+package com.vaadin.demo.sampler.features.link;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.VerticalLayout;
+
+public class LinkNoDecorationsExample extends VerticalLayout {
+
+ private static final String CAPTION = "Open Google in new window";
+ private static final String TOOLTIP = "http://www.google.com (opens in new window)";
+ private static final ThemeResource ICON = new ThemeResource(
+ "icons/icon_world.gif");
+
+ public LinkNoDecorationsExample() {
+ setSpacing(true);
+
+ // Link w/ text and tooltip
+ Link l = new Link(CAPTION,
+ new ExternalResource("http://www.google.com"));
+ l.setTargetName("_blank");
+ l.setTargetBorder(Link.TARGET_BORDER_NONE);
+ l.setDescription(TOOLTIP);
+ addComponent(l);
+
+ // Link w/ text, icon and tooltip
+ l = new Link(CAPTION, new ExternalResource("http://www.google.com"));
+ l.setTargetName("_blank");
+ l.setTargetBorder(Link.TARGET_BORDER_NONE);
+ l.setDescription(TOOLTIP);
+ l.setIcon(ICON);
+ addComponent(l);
+
+ // Link w/ icon and tooltip
+ l = new Link();
+ l.setResource(new ExternalResource("http://www.google.com"));
+ l.setTargetName("_blank");
+ l.setTargetBorder(Link.TARGET_BORDER_NONE);
+ l.setDescription(TOOLTIP);
+ l.setIcon(ICON);
+ addComponent(l);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/link/LinkSizedWindow.java b/src/com/vaadin/demo/sampler/features/link/LinkSizedWindow.java
new file mode 100644
index 0000000000..9b8f8e5488
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/LinkSizedWindow.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.sampler.features.link;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.buttons.ButtonLink;
+import com.vaadin.ui.Link;
+
+public class LinkSizedWindow extends Feature {
+
+ @Override
+ public String getName() {
+ return "Link, sized window";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Links can configure the size of the opened window.<br/>These links open a small fixed size window without decorations.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Link.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LinkCurrentWindow.class, LinkNoDecorations.class,
+ ButtonLink.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/link/LinkSizedWindowExample.java b/src/com/vaadin/demo/sampler/features/link/LinkSizedWindowExample.java
new file mode 100644
index 0000000000..8d47deea45
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/link/LinkSizedWindowExample.java
@@ -0,0 +1,52 @@
+package com.vaadin.demo.sampler.features.link;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.VerticalLayout;
+
+public class LinkSizedWindowExample extends VerticalLayout {
+
+ private static final String CAPTION = "Open Google in small window";
+ private static final String TOOLTIP = "http://www.google.com (opens in small window)";
+ private static final ThemeResource ICON = new ThemeResource(
+ "icons/icon_world.gif");
+ private static final Resource TARGET = new ExternalResource(
+ "http://www.google.com/m");
+
+ public LinkSizedWindowExample() {
+ setSpacing(true);
+
+ // Link w/ text and tooltip
+ Link l = new Link(CAPTION, TARGET);
+ l.setTargetName("_blank");
+ l.setTargetWidth(300);
+ l.setTargetHeight(300);
+ l.setTargetBorder(Link.TARGET_BORDER_NONE);
+ l.setDescription(TOOLTIP);
+ addComponent(l);
+
+ // Link w/ text, icon and tooltip
+ l = new Link(CAPTION, TARGET);
+ l.setTargetName("_blank");
+ l.setTargetWidth(300);
+ l.setTargetHeight(300);
+ l.setTargetBorder(Link.TARGET_BORDER_NONE);
+ l.setDescription(TOOLTIP);
+ l.setIcon(ICON);
+ addComponent(l);
+
+ // Link w/ icon and tooltip
+ l = new Link();
+ l.setResource(TARGET);
+ l.setTargetName("_blank");
+ l.setTargetWidth(300);
+ l.setTargetHeight(300);
+ l.setTargetBorder(Link.TARGET_BORDER_NONE);
+ l.setDescription(TOOLTIP);
+ l.setIcon(ICON);
+ addComponent(l);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/75-NotificationCustom.png b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationCustom.png
new file mode 100644
index 0000000000..87aebc88f0
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationCustom.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/notifications/75-NotificationError.png b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationError.png
new file mode 100644
index 0000000000..e16a49ddef
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationError.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/notifications/75-NotificationHumanized.png b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationHumanized.png
new file mode 100644
index 0000000000..a2dd395f84
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationHumanized.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/notifications/75-NotificationTray.png b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationTray.png
new file mode 100644
index 0000000000..31c256673f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationTray.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/notifications/75-NotificationWarning.png b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationWarning.png
new file mode 100644
index 0000000000..0626d17bda
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/75-NotificationWarning.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationCustom.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationCustom.java
new file mode 100644
index 0000000000..dc6780d3c6
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationCustom.java
@@ -0,0 +1,45 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class NotificationCustom extends Feature {
+
+ @Override
+ public String getName() {
+ return "Customized notification";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A notification can have a caption, a richtext"
+ + " description, and an icon. Position and delay can"
+ + " also be customized.<br/>Note that more often than"
+ + " not, less is more: try to make the messages short"
+ + " and to the point.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class),
+ new APIResource(Window.Notification.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NotificationHumanized.class,
+ NotificationWarning.class, NotificationError.class,
+ NotificationTray.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "Monolog Boxes and Transparent Messages",
+ "http://humanized.com/weblog/2006/09/11/monolog_boxes_and_transparent_messages/") };
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationCustomExample.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationCustomExample.java
new file mode 100644
index 0000000000..ce20e77827
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationCustomExample.java
@@ -0,0 +1,133 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.Slider;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Window.Notification;
+
+public class NotificationCustomExample extends VerticalLayout {
+
+ private static final Object CAPTION_PROPERTY = new Object();
+
+ public NotificationCustomExample() {
+ setSpacing(true);
+ setWidth(null); // layout will grow with content
+
+ final TextField caption = new TextField("Caption", "Message sent");
+ caption
+ .setDescription("Main info; a short caption-only notification is often most effective.");
+ caption.setWidth("200px");
+ addComponent(caption);
+
+ final RichTextArea description = new RichTextArea();
+ description.setValue("<p>to <i>john.doe@example.com</i></p>");
+ description.setCaption("Description");
+ description
+ .setDescription("Additional information; try to keep it short.");
+ addComponent(description);
+
+ HorizontalLayout horiz = new HorizontalLayout();
+ horiz.setSpacing(true);
+ addComponent(horiz);
+
+ final NativeSelect position = new NativeSelect("Position");
+ position.setNullSelectionAllowed(false);
+ horiz.addComponent(position);
+ initPositionItems(position);
+
+ final NativeSelect style = new NativeSelect("Style");
+ style.setNullSelectionAllowed(false);
+ horiz.addComponent(style);
+ initTypeItems(style);
+
+ final Slider delay = new Slider("Delay (msec), -1 means click to hide");
+ delay
+ .setDescription("Delay before fading<br/>Pull all the way to the left to get -1, which means forever (click to hide).");
+ delay.setWidth("100%"); // 'description' will push width
+ delay.setMin(Notification.DELAY_FOREVER);
+ delay.setMax(10000);
+ addComponent(delay);
+
+ // TODO icon select
+
+ Button show = new Button("Show notification",
+ new Button.ClickListener() {
+ // "Inline" click listener; this is where the
+ // notification is actually created and shown.
+ public void buttonClick(ClickEvent event) {
+ // create Notification instance and customize
+ Notification n = new Notification((String) caption
+ .getValue(), (String) description.getValue(),
+ (Integer) style.getValue());
+ n.setPosition((Integer) position.getValue());
+ Double d = (Double) delay.getValue();
+ n.setDelayMsec(d.intValue()); // sec->msec
+ getWindow().showNotification(n);
+ }
+ });
+ addComponent(show);
+ setComponentAlignment(show, Alignment.MIDDLE_RIGHT);
+
+ }
+
+ /*
+ * Helper to fill the position select with the various possibilities
+ */
+ private void initPositionItems(NativeSelect position) {
+ position.addContainerProperty(CAPTION_PROPERTY, String.class, null);
+ position.setItemCaptionPropertyId(CAPTION_PROPERTY);
+ Item i = position.addItem(Notification.POSITION_TOP_LEFT);
+ Property c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Top left");
+ i = position.addItem(Notification.POSITION_CENTERED_TOP);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Top centered");
+ i = position.addItem(Notification.POSITION_TOP_RIGHT);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Top right");
+ i = position.addItem(Notification.POSITION_CENTERED);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Centered");
+ i = position.addItem(Notification.POSITION_BOTTOM_LEFT);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Bottom left");
+ i = position.addItem(Notification.POSITION_CENTERED_BOTTOM);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Bottom, centered");
+ i = position.addItem(Notification.POSITION_BOTTOM_RIGHT);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Bottom right");
+ position.setValue(Notification.POSITION_CENTERED);
+ }
+
+ /*
+ * Helper to fill the position select with the various possibilities
+ */
+ private void initTypeItems(NativeSelect type) {
+ type.addContainerProperty(CAPTION_PROPERTY, String.class, null);
+ type.setItemCaptionPropertyId(CAPTION_PROPERTY);
+ Item i = type.addItem(Notification.TYPE_HUMANIZED_MESSAGE);
+ Property c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Humanized");
+ i = type.addItem(Notification.TYPE_WARNING_MESSAGE);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Warning");
+ i = type.addItem(Notification.TYPE_ERROR_MESSAGE);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Error");
+ i = type.addItem(Notification.TYPE_TRAY_NOTIFICATION);
+ c = i.getItemProperty(CAPTION_PROPERTY);
+ c.setValue("Tray");
+
+ type.setValue(Notification.TYPE_HUMANIZED_MESSAGE);
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationError.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationError.java
new file mode 100644
index 0000000000..406249658a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationError.java
@@ -0,0 +1,46 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class NotificationError extends Feature {
+
+ @Override
+ public String getName() {
+ return "Error notification";
+ }
+
+ @Override
+ public String getDescription() {
+ return "<p>The <i>Error</i> notification is modal, and is to be used for"
+ + " messages that must be seen by the user.<br/>"
+ + " The <i>Error</i> message must be closed by clicking"
+ + " the notification.</p><p>Candidates for an"
+ + " <i>Error</i> notification include 'Save failed',"
+ + " 'Permission denied', and other situations that the"
+ + " user must be made aware of.<br/>It's a good idea to"
+ + " provide hints about what went wrong, and how the user'"
+ + " can proceed to correct the situation.</p>";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class),
+ new APIResource(Window.Notification.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NotificationHumanized.class,
+ NotificationTray.class, NotificationWarning.class,
+ NotificationCustom.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationErrorExample.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationErrorExample.java
new file mode 100644
index 0000000000..3860e7fd17
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationErrorExample.java
@@ -0,0 +1,42 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Window.Notification;
+
+public class NotificationErrorExample extends VerticalLayout {
+
+ public NotificationErrorExample() {
+ setSpacing(true);
+ setWidth(null); // layout will grow with content
+
+ final TextField caption = new TextField("Caption", "Upload failed");
+ caption.setWidth("200px");
+ addComponent(caption);
+
+ final TextField description = new TextField(
+ "Description",
+ "Invoices-2008.csv could not be read.<br/>"
+ + "Perhaps the file is damaged, or in the wrong format?<br/>"
+ + "Try re-exporting and uploading the file again.");
+ description.setWidth("300px");
+ addComponent(description);
+
+ Button show = new Button("Show notification",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ (String) caption.getValue(),
+ (String) description.getValue(),
+ Notification.TYPE_ERROR_MESSAGE);
+
+ }
+ });
+ addComponent(show);
+ setComponentAlignment(show, Alignment.MIDDLE_RIGHT);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationHumanized.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationHumanized.java
new file mode 100644
index 0000000000..dfc14d3466
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationHumanized.java
@@ -0,0 +1,48 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class NotificationHumanized extends Feature {
+
+ @Override
+ public String getName() {
+ return "Humanized notification";
+ }
+
+ @Override
+ public String getDescription() {
+ return "<p>The <i>Humanized</i> notification is an implementation of"
+ + " the <i>transparent message</i> -pattern, and can be used"
+ + " to indicate non-critical events while interrupting"
+ + " the user as little as possible.<br/>"
+ + "The <i>Humanized</i> message quickly fades away once"
+ + " the user interacts with the application (i.e. moves"
+ + " mouse, types).</p><p>Candidates for a"
+ + " <i>Humanized</i> notification include 'XYZ saved',"
+ + " 'Added XYZ', and other messages that the user can"
+ + " safely ignore, once the application is familliar.</p>";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class),
+ new APIResource(Window.Notification.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NotificationTray.class, NotificationWarning.class,
+ NotificationError.class, NotificationCustom.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "Monolog Boxes and Transparent Messages",
+ "http://humanized.com/weblog/2006/09/11/monolog_boxes_and_transparent_messages/") };
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationHumanizedExample.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationHumanizedExample.java
new file mode 100644
index 0000000000..8d70a2e2b9
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationHumanizedExample.java
@@ -0,0 +1,37 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class NotificationHumanizedExample extends VerticalLayout {
+
+ public NotificationHumanizedExample() {
+ setSpacing(true);
+ setWidth(null); // layout will grow with content
+
+ final TextField caption = new TextField("Caption", "Document saved");
+ caption.setWidth("200px");
+ addComponent(caption);
+
+ final TextField description = new TextField("Description",
+ "Invoices-2008.csv");
+ description.setWidth("300px");
+ addComponent(description);
+
+ Button show = new Button("Show notification",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ (String) caption.getValue(),
+ (String) description.getValue());
+
+ }
+ });
+ addComponent(show);
+ setComponentAlignment(show, Alignment.MIDDLE_RIGHT);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationTray.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationTray.java
new file mode 100644
index 0000000000..9401f90d0b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationTray.java
@@ -0,0 +1,49 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class NotificationTray extends Feature {
+
+ @Override
+ public String getName() {
+ return "Tray notification";
+ }
+
+ @Override
+ public String getDescription() {
+ return "<p>The <i>Tray</i> notification shows up in the lower right corner,"
+ + " and is meant to interrupt the user as little as possible"
+ + " even if it's shown for a while. "
+ + "The <i>Tray</i> message fades away after a few moments"
+ + " once the user interacts with the application (e.g. moves"
+ + " mouse, types)</p><p>Candidates for a"
+ + " <i>Tray</i> notification include 'New message received',"
+ + " 'Job XYZ completed' &ndash; generally notifications about events"
+ + " that have been delayed, or occur in the background"
+ + " (as opposed to being a direct result of the users last action.)</p>";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class),
+ new APIResource(Window.Notification.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NotificationHumanized.class,
+ NotificationWarning.class, NotificationError.class,
+ NotificationCustom.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "Monolog Boxes and Transparent Messages",
+ "http://humanized.com/weblog/2006/09/11/monolog_boxes_and_transparent_messages/") };
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationTrayExample.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationTrayExample.java
new file mode 100644
index 0000000000..a7d78ebfca
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationTrayExample.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Window.Notification;
+
+public class NotificationTrayExample extends VerticalLayout {
+
+ public NotificationTrayExample() {
+ setSpacing(true);
+ setWidth(null); // layout will grow with content
+
+ final TextField caption = new TextField("Caption", "New message");
+ caption.setWidth("200px");
+ addComponent(caption);
+
+ final TextField description = new TextField("Description",
+ "<b>John:</b> Could you upload Invoices-2008.csv so that...");
+ description.setWidth("300px");
+ addComponent(description);
+
+ Button show = new Button("Show notification",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ (String) caption.getValue(),
+ (String) description.getValue(),
+ Notification.TYPE_TRAY_NOTIFICATION);
+
+ }
+ });
+ addComponent(show);
+ setComponentAlignment(show, Alignment.MIDDLE_RIGHT);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationWarning.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationWarning.java
new file mode 100644
index 0000000000..303361c6d1
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationWarning.java
@@ -0,0 +1,49 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class NotificationWarning extends Feature {
+
+ @Override
+ public String getName() {
+ return "Warning notification";
+ }
+
+ @Override
+ public String getDescription() {
+ return "<p>The <i>Warning</i> notification is an implementation of"
+ + " the <i>transparent message</i> -pattern, and is meant"
+ + " to interrupt the user as little as possible, while"
+ + " still drawing the needed attention."
+ + "The <i>Warning</i> message fades away after a few moments"
+ + " once the user interacts with the application (e.g. moves"
+ + " mouse, types)</p><p>Candidates for a"
+ + " <i>Warning</i> notification include 'You canceled XYZ',"
+ + " 'XYZ deleted', and other situations that the user should"
+ + " be made aware of, but are probably intentional.</p>";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class),
+ new APIResource(Window.Notification.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NotificationHumanized.class,
+ NotificationTray.class, NotificationError.class,
+ NotificationCustom.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "Monolog Boxes and Transparent Messages",
+ "http://humanized.com/weblog/2006/09/11/monolog_boxes_and_transparent_messages/") };
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/notifications/NotificationWarningExample.java b/src/com/vaadin/demo/sampler/features/notifications/NotificationWarningExample.java
new file mode 100644
index 0000000000..ae98aeb739
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/notifications/NotificationWarningExample.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.notifications;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Window.Notification;
+
+public class NotificationWarningExample extends VerticalLayout {
+
+ public NotificationWarningExample() {
+ setSpacing(true);
+ setWidth(null); // layout will grow with content
+
+ final TextField caption = new TextField("Caption", "Upload canceled");
+ caption.setWidth("200px");
+ addComponent(caption);
+
+ final TextField description = new TextField("Description",
+ "Invoices-2008.csv will not be processed");
+ description.setWidth("300px");
+ addComponent(description);
+
+ Button show = new Button("Show notification",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ (String) caption.getValue(),
+ (String) description.getValue(),
+ Notification.TYPE_WARNING_MESSAGE);
+
+ }
+ });
+ addComponent(show);
+ setComponentAlignment(show, Alignment.MIDDLE_RIGHT);
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/panels/75-PanelBasic.png b/src/com/vaadin/demo/sampler/features/panels/75-PanelBasic.png
new file mode 100644
index 0000000000..3307b22067
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/panels/75-PanelBasic.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/panels/75-PanelLight.png b/src/com/vaadin/demo/sampler/features/panels/75-PanelLight.png
new file mode 100644
index 0000000000..c36e16af47
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/panels/75-PanelLight.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/panels/PanelBasic.java b/src/com/vaadin/demo/sampler/features/panels/PanelBasic.java
new file mode 100644
index 0000000000..5d659b04a5
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/panels/PanelBasic.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.panels;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Panel;
+
+public class PanelBasic extends Feature {
+ @Override
+ public String getName() {
+ return "Panel";
+ }
+
+ @Override
+ public String getDescription() {
+ return "";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Panel.class),
+ new APIResource(Layout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { PanelLight.class, FeatureSet.Layouts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/panels/PanelBasicExample.java b/src/com/vaadin/demo/sampler/features/panels/PanelBasicExample.java
new file mode 100644
index 0000000000..498337ff43
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/panels/PanelBasicExample.java
@@ -0,0 +1,47 @@
+package com.vaadin.demo.sampler.features.panels;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+public class PanelBasicExample extends VerticalLayout implements ClickListener {
+
+ private Panel panel;
+
+ public PanelBasicExample() {
+ setSpacing(true);
+
+ // Panel 1 - with caption
+ panel = new Panel("This is a standard Panel");
+ panel.setHeight("200px"); // we want scrollbars
+
+ // let's adjust the panels default layout (a VerticalLayout)
+ VerticalLayout layout = (VerticalLayout) panel.getLayout();
+ layout.setMargin(true); // we want a margin
+ layout.setSpacing(true); // and spacing between components
+ addComponent(panel);
+
+ // Let's add a few rows to provoke scrollbars:
+ for (int i = 0; i < 20; i++) {
+ panel.addComponent(new Label(
+ "The quick brown fox jumps over the lazy dog."));
+ }
+
+ // Caption toggle:
+ Button b = new Button("Toggle caption");
+ b.addListener(this);
+ addComponent(b);
+
+ }
+
+ public void buttonClick(ClickEvent event) {
+ if (panel.getCaption().equals("")) {
+ panel.setCaption("This is a standard Panel");
+ } else {
+ panel.setCaption("");
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/panels/PanelLight.java b/src/com/vaadin/demo/sampler/features/panels/PanelLight.java
new file mode 100644
index 0000000000..ddb4138913
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/panels/PanelLight.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.panels;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Panel;
+
+public class PanelLight extends Feature {
+ @Override
+ public String getName() {
+ return "Panel, light style";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The 'light' panel has less decorations than the regular Panel style.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Panel.class),
+ new APIResource(Layout.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { PanelBasic.class, FeatureSet.Layouts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/panels/PanelLightExample.java b/src/com/vaadin/demo/sampler/features/panels/PanelLightExample.java
new file mode 100644
index 0000000000..38aa53ca5f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/panels/PanelLightExample.java
@@ -0,0 +1,49 @@
+package com.vaadin.demo.sampler.features.panels;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+public class PanelLightExample extends VerticalLayout implements ClickListener {
+
+ private Panel panel;
+
+ public PanelLightExample() {
+ setSpacing(true);
+
+ setSpacing(true);
+
+ // Panel 1 - with caption
+ panel = new Panel("This is a light Panel");
+ panel.setStyleName(Panel.STYLE_LIGHT);
+ panel.setHeight("200px"); // we want scrollbars
+
+ // let's adjust the panels default layout (a VerticalLayout)
+ VerticalLayout layout = (VerticalLayout) panel.getLayout();
+ layout.setMargin(true); // we want a margin
+ layout.setSpacing(true); // and spacing between components
+ addComponent(panel);
+
+ // Let's add a few rows to provoke scrollbars:
+ for (int i = 0; i < 20; i++) {
+ panel.addComponent(new Label(
+ "The quick brown fox jumps over the lazy dog."));
+ }
+
+ // Caption toggle:
+ Button b = new Button("Toggle caption");
+ b.addListener(this);
+ addComponent(b);
+ }
+
+ public void buttonClick(ClickEvent event) {
+ if (panel.getCaption() == null) {
+ panel.setCaption("This is a light Panel");
+ } else {
+ panel.setCaption(null);
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxContains.png b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxContains.png
new file mode 100644
index 0000000000..af8cdf2215
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxContains.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxInputPrompt.png b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxInputPrompt.png
new file mode 100644
index 0000000000..3ef7a48faa
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxInputPrompt.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxNewItems.png b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxNewItems.png
new file mode 100644
index 0000000000..c79228fdcf
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxNewItems.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxPlain.png b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxPlain.png
new file mode 100644
index 0000000000..603c8c6cab
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxPlain.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxStartsWith.png b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxStartsWith.png
new file mode 100644
index 0000000000..2b5d0f1bd0
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-ComboBoxStartsWith.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-ListSelectMultiple.png b/src/com/vaadin/demo/sampler/features/selects/75-ListSelectMultiple.png
new file mode 100644
index 0000000000..628b5787f8
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-ListSelectMultiple.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-ListSelectSingle.png b/src/com/vaadin/demo/sampler/features/selects/75-ListSelectSingle.png
new file mode 100644
index 0000000000..b4ac1f4999
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-ListSelectSingle.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-NativeSelection.png b/src/com/vaadin/demo/sampler/features/selects/75-NativeSelection.png
new file mode 100644
index 0000000000..8d39ff69b5
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-NativeSelection.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/75-TwinColumnSelect.png b/src/com/vaadin/demo/sampler/features/selects/75-TwinColumnSelect.png
new file mode 100644
index 0000000000..b8e0dae88a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/75-TwinColumnSelect.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxContains.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxContains.java
new file mode 100644
index 0000000000..5c6a30a145
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxContains.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.ComboBox;
+
+public class ComboBoxContains extends Feature {
+ @Override
+ public String getName() {
+ return "Combobox, suggesting (contains)";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A drop-down selection component with single item selection.<br/>"
+ + " A 'contains' filter has been used in this example,"
+ + " so you can key in some text and only the options"
+ + " containing your input will be shown.<br/>"
+ + " Because there are so many options, they are loaded on-demand"
+ + " (\"lazy-loading\") from the server when paging or"
+ + " filtering. This behavior is built-in and requires no extra"
+ + " code.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ComboBox.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ComboBoxPlain.class, ComboBoxStartsWith.class,
+ ComboBoxNewItems.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxContainsExample.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxContainsExample.java
new file mode 100644
index 0000000000..57818231fd
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxContainsExample.java
@@ -0,0 +1,50 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.AbstractSelect.Filtering;
+
+public class ComboBoxContainsExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ public ComboBoxContainsExample() {
+ setSpacing(true);
+
+ // Creates a new combobox using an existing container
+ ComboBox l = new ComboBox("Please select your country", ExampleUtil
+ .getStaticISO3166Container());
+
+ // Sets the combobox to show a certain property as the item caption
+ l.setItemCaptionPropertyId(ExampleUtil.iso3166_PROPERTY_NAME);
+ l.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+
+ // Sets the icon to use with the items
+ l.setItemIconPropertyId(ExampleUtil.iso3166_PROPERTY_FLAG);
+
+ // Set a reasonable width
+ l.setWidth(350, UNITS_PIXELS);
+
+ // Set the appropriate filtering mode for this example
+ l.setFilteringMode(Filtering.FILTERINGMODE_CONTAINS);
+ l.setImmediate(true);
+ l.addListener(this);
+
+ // Disallow null selections
+ l.setNullSelectionAllowed(false);
+
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ Property selected = ExampleUtil.getStaticISO3166Container()
+ .getContainerProperty(event.getProperty().toString(), "name");
+ getWindow().showNotification("Selected country: " + selected);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPrompt.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPrompt.java
new file mode 100644
index 0000000000..3021e1761a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPrompt.java
@@ -0,0 +1,44 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.text.TextFieldInputPrompt;
+import com.vaadin.ui.ComboBox;
+
+public class ComboBoxInputPrompt extends Feature {
+ @Override
+ public String getName() {
+ return "Combobox with input prompt";
+ }
+
+ @Override
+ public String getDescription() {
+ return "ComboBox is a drop-down selection component with single item selection."
+ + " It can have an <i>input prompt</i> - a textual hint that is shown within"
+ + " the select when no value is selected.<br/>"
+ + " You can use an input prompt instead of a caption to save"
+ + " space, but only do so if the function of the ComboBox is"
+ + " still clear when a value is selected and the prompt is no"
+ + " longer visible.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ComboBox.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ComboBoxStartsWith.class, ComboBoxContains.class,
+ ComboBoxNewItems.class, TextFieldInputPrompt.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "UI Patterns, Input Prompt",
+ "http://ui-patterns.com/pattern/InputPrompt") };
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPromptExample.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPromptExample.java
new file mode 100644
index 0000000000..b326a636de
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxInputPromptExample.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.VerticalLayout;
+
+public class ComboBoxInputPromptExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private static final String[] cities = new String[] { "Berlin", "Brussels",
+ "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" };
+
+ public ComboBoxInputPromptExample() {
+ setMargin(true); // for looks: more 'air'
+
+ // Create & set input prompt
+ ComboBox l = new ComboBox();
+ l.setInputPrompt("Please select a city");
+
+ // configure & load content
+ l.setImmediate(true);
+ l.addListener(this);
+ for (int i = 0; i < cities.length; i++) {
+ l.addItem(cities[i]);
+ }
+
+ // add to the layout
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Selected city: " + event.getProperty());
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItems.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItems.java
new file mode 100644
index 0000000000..1b4508eb19
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItems.java
@@ -0,0 +1,45 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.ComboBox;
+
+public class ComboBoxNewItems extends Feature {
+ @Override
+ public String getName() {
+ return "Combobox, enter new items";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A drop-down selection component with single item selection.<br/>"
+ + " This example also allows you to input your own"
+ + " choice - your input will be added to the selection"
+ + " of available choices. This behavior is built-in and can"
+ + " be enabled with one method call. Note that by using this"
+ + " feature, one can easily create <i>suggestion box</i> -type"
+ + " inputs that for example remembers the users previous input,"
+ + " or provides suggestions from a list of popular choices."
+ + " Configured like this (and optionally with a filter), the"
+ + " ComboBox can be a powerful alternative to TextField.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ComboBox.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ComboBoxPlain.class, ComboBoxStartsWith.class,
+ ComboBoxContains.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItemsExample.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItemsExample.java
new file mode 100644
index 0000000000..d3c3717195
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxNewItemsExample.java
@@ -0,0 +1,51 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.VerticalLayout;
+
+public class ComboBoxNewItemsExample extends VerticalLayout implements
+ Property.ValueChangeListener, AbstractSelect.NewItemHandler {
+ private static final String[] cities = new String[] { "Berlin", "Brussels",
+ "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" };
+ private ComboBox l;
+ private Boolean lastAdded = false;
+
+ public ComboBoxNewItemsExample() {
+ setSpacing(true);
+
+ l = new ComboBox("Please select a city");
+ for (int i = 0; i < cities.length; i++) {
+ l.addItem(cities[i]);
+ }
+
+ l.setNewItemsAllowed(true);
+ l.setNewItemHandler(this);
+ l.setImmediate(true);
+ l.addListener(this);
+
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ if (!lastAdded) {
+ getWindow().showNotification(
+ "Selected city: " + event.getProperty());
+ }
+ lastAdded = false;
+ }
+
+ public void addNewItem(String newItemCaption) {
+ if (!l.containsId(newItemCaption)) {
+ getWindow().showNotification("Added city: " + newItemCaption);
+ lastAdded = true;
+ l.addItem(newItemCaption);
+ l.setValue(newItemCaption);
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxPlain.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxPlain.java
new file mode 100644
index 0000000000..18f1ea3a5e
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxPlain.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.ComboBox;
+
+public class ComboBoxPlain extends Feature {
+ @Override
+ public String getName() {
+ return "Combobox";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A drop-down selection component with single item selection."
+ + " Shown here is the most basic variant, which basically"
+ + " provides the same functionality as a NativeSelect with"
+ + " added lazy-loading if there are many options.<br/>"
+ + " See related examples for more advanced features.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ComboBox.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ComboBoxStartsWith.class, ComboBoxContains.class,
+ ComboBoxNewItems.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxPlainExample.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxPlainExample.java
new file mode 100644
index 0000000000..612cc70f59
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxPlainExample.java
@@ -0,0 +1,37 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.AbstractSelect.Filtering;
+
+public class ComboBoxPlainExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private static final String[] cities = new String[] { "Berlin", "Brussels",
+ "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" };
+
+ public ComboBoxPlainExample() {
+ setSpacing(true);
+
+ ComboBox l = new ComboBox("Please select a city");
+ for (int i = 0; i < cities.length; i++) {
+ l.addItem(cities[i]);
+ }
+
+ l.setFilteringMode(Filtering.FILTERINGMODE_OFF);
+ l.setImmediate(true);
+ l.addListener(this);
+
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Selected city: " + event.getProperty());
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWith.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWith.java
new file mode 100644
index 0000000000..1f2ca22256
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWith.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.ComboBox;
+
+public class ComboBoxStartsWith extends Feature {
+ @Override
+ public String getName() {
+ return "Combobox, suggesting (starts-with)";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A drop-down selection component with single item selection.<br/>"
+ + " A 'starts-with' filter has been used in this example,"
+ + " so you can key in some text and only the options"
+ + " beginning with your input will be shown.<br/>"
+ + " Because there are so many options, they are loaded on-demand"
+ + " (\"lazy-loading\") from the server when paging or"
+ + " filtering. This behavior is built-in and requires no extra"
+ + " code.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ComboBox.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ComboBoxPlain.class, ComboBoxContains.class,
+ ComboBoxNewItems.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWithExample.java b/src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWithExample.java
new file mode 100644
index 0000000000..d29a429890
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ComboBoxStartsWithExample.java
@@ -0,0 +1,50 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.AbstractSelect.Filtering;
+
+public class ComboBoxStartsWithExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ public ComboBoxStartsWithExample() {
+ setSpacing(true);
+
+ // Creates a new combobox using an existing container
+ ComboBox l = new ComboBox("Please select your country", ExampleUtil
+ .getStaticISO3166Container());
+
+ // Sets the combobox to show a certain property as the item caption
+ l.setItemCaptionPropertyId(ExampleUtil.iso3166_PROPERTY_NAME);
+ l.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+
+ // Sets the icon to use with the items
+ l.setItemIconPropertyId(ExampleUtil.iso3166_PROPERTY_FLAG);
+
+ // Set a reasonable width
+ l.setWidth(350, UNITS_PIXELS);
+
+ // Set the appropriate filtering mode for this example
+ l.setFilteringMode(Filtering.FILTERINGMODE_STARTSWITH);
+ l.setImmediate(true);
+ l.addListener(this);
+
+ // Disallow null selections
+ l.setNullSelectionAllowed(false);
+
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ Property selected = ExampleUtil.getStaticISO3166Container()
+ .getContainerProperty(event.getProperty().toString(), "name");
+ getWindow().showNotification("Selected country: " + selected);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ListSelectMultiple.java b/src/com/vaadin/demo/sampler/features/selects/ListSelectMultiple.java
new file mode 100644
index 0000000000..5e3f13fff2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ListSelectMultiple.java
@@ -0,0 +1,41 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.ListSelect;
+
+public class ListSelectMultiple extends Feature {
+ @Override
+ public String getName() {
+ return "List select, multiple selections";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A simple list select component with multiple item selection."
+ + " You can allow or disallow <i>null selection</i> - i.e the"
+ + " possibility to make an empty selection. Null selection is"
+ + " allowed in this example.<br/>"
+ + "You can select multiple items from the list by holding"
+ + " the CTRL of SHIFT key while clicking the items.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ListSelect.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NativeSelection.class, ListSelectSingle.class,
+ TwinColumnSelect.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ListSelectMultipleExample.java b/src/com/vaadin/demo/sampler/features/selects/ListSelectMultipleExample.java
new file mode 100644
index 0000000000..629b1b7326
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ListSelectMultipleExample.java
@@ -0,0 +1,37 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.ListSelect;
+import com.vaadin.ui.VerticalLayout;
+
+public class ListSelectMultipleExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private static final String[] cities = new String[] { "Berlin", "Brussels",
+ "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" };
+
+ public ListSelectMultipleExample() {
+ setSpacing(true);
+
+ ListSelect l = new ListSelect("Please select some cities");
+ for (int i = 0; i < cities.length; i++) {
+ l.addItem(cities[i]);
+ }
+ l.setRows(7);
+ l.setNullSelectionAllowed(true);
+ l.setMultiSelect(true);
+ l.setImmediate(true);
+ l.addListener(this);
+
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Selected cities: " + event.getProperty());
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ListSelectSingle.java b/src/com/vaadin/demo/sampler/features/selects/ListSelectSingle.java
new file mode 100644
index 0000000000..352261a047
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ListSelectSingle.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.ListSelect;
+
+public class ListSelectSingle extends Feature {
+ @Override
+ public String getName() {
+ return "List select, single selection";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A simple list select component with single item selection.<br/>"
+ + "You can allow or disallow <i>null selection</i> - i.e the"
+ + " possibility to make an empty selection. Null selection is"
+ + " not allowed in this example.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(ListSelect.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NativeSelection.class, ListSelectMultiple.class,
+ TwinColumnSelect.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/ListSelectSingleExample.java b/src/com/vaadin/demo/sampler/features/selects/ListSelectSingleExample.java
new file mode 100644
index 0000000000..90c4ac2a63
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/ListSelectSingleExample.java
@@ -0,0 +1,41 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.ListSelect;
+import com.vaadin.ui.VerticalLayout;
+
+public class ListSelectSingleExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private static final List cities = Arrays.asList(new String[] { "Berlin",
+ "Brussels", "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" });
+
+ public ListSelectSingleExample() {
+ setSpacing(true);
+
+ // 'Shorthand' constructor - also supports data binding using Containers
+ ListSelect citySelect = new ListSelect("Please select a city", cities);
+
+ citySelect.setRows(7); // perfect length in out case
+ citySelect.setNullSelectionAllowed(false); // user can not 'unselect'
+ citySelect.select("Berlin"); // select this by default
+ citySelect.setImmediate(true); // send the change to the server at once
+ citySelect.addListener(this); // react when the user selects something
+
+ addComponent(citySelect);
+ }
+
+ /*
+ * Shows a notification when a selection is made. The listener will be
+ * called whenever the value of the component changes, i.e when the user
+ * makes a new selection.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Selected city: " + event.getProperty());
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/NativeSelection.java b/src/com/vaadin/demo/sampler/features/selects/NativeSelection.java
new file mode 100644
index 0000000000..95523cddf1
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/NativeSelection.java
@@ -0,0 +1,45 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.NativeSelect;
+
+public class NativeSelection extends Feature {
+ @Override
+ public String getName() {
+ return "Native select";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A NativeSelect is a a simple drop-down list"
+ + " for selecting one item. It is called <i>native</i>"
+ + " because it uses the look and feel from the browser in use.<br/>"
+ + " The ComboBox component is a much more versatile variant,"
+ + " but without the native look and feel.<br/>"
+ + " From a usability standpoint, you might also want to"
+ + " consider using a ListSelect in single-select-mode, so that"
+ + " the user can see all options right away.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(NativeSelect.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { ComboBoxPlain.class, ListSelectSingle.class,
+ FeatureSet.Selects.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/NativeSelectionExample.java b/src/com/vaadin/demo/sampler/features/selects/NativeSelectionExample.java
new file mode 100644
index 0000000000..63976bfc70
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/NativeSelectionExample.java
@@ -0,0 +1,37 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.VerticalLayout;
+
+public class NativeSelectionExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private static final String[] cities = new String[] { "Berlin", "Brussels",
+ "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" };
+
+ public NativeSelectionExample() {
+ setSpacing(true);
+
+ NativeSelect l = new NativeSelect("Please select a city");
+ for (int i = 0; i < cities.length; i++) {
+ l.addItem(cities[i]);
+ }
+
+ l.setNullSelectionAllowed(false);
+ l.setValue("Berlin");
+ l.setImmediate(true);
+ l.addListener(this);
+
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Selected city: " + event.getProperty());
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/TwinColumnSelect.java b/src/com/vaadin/demo/sampler/features/selects/TwinColumnSelect.java
new file mode 100644
index 0000000000..3522a4e8ca
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/TwinColumnSelect.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.TwinColSelect;
+
+public class TwinColumnSelect extends Feature {
+ @Override
+ public String getName() {
+ return "Twin column select (list builder)";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The TwinColumnSelect is a multiple selection component"
+ + " that shows two lists side by side. The list on the left"
+ + " shows the available items and the list on the right shows"
+ + " the selected items. <br>You can select items"
+ + " from the list on the left and click on the >> button to move"
+ + " them to the list on the right. Items can be moved back by"
+ + " selecting them and clicking on the << button.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TwinColSelect.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NativeSelection.class, ListSelectMultiple.class,
+ ListSelectSingle.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "Open Source Design Pattern Library; List Builder",
+ "http://www.uidesignpatterns.org/content/list-builder") };
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/selects/TwinColumnSelectExample.java b/src/com/vaadin/demo/sampler/features/selects/TwinColumnSelectExample.java
new file mode 100644
index 0000000000..b35a4d60d7
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/selects/TwinColumnSelectExample.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.selects;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.TwinColSelect;
+import com.vaadin.ui.VerticalLayout;
+
+public class TwinColumnSelectExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private static final String[] cities = new String[] { "Berlin", "Brussels",
+ "Helsinki", "Madrid", "Oslo", "Paris", "Stockholm" };
+
+ public TwinColumnSelectExample() {
+ setSpacing(true);
+
+ TwinColSelect l = new TwinColSelect("Please select some cities");
+ for (int i = 0; i < cities.length; i++) {
+ l.addItem(cities[i]);
+ }
+ l.setRows(7);
+ l.setNullSelectionAllowed(true);
+ l.setMultiSelect(true);
+ l.setImmediate(true);
+ l.addListener(this);
+
+ addComponent(l);
+ }
+
+ /*
+ * Shows a notification when a selection is made.
+ */
+ public void valueChange(ValueChangeEvent event) {
+ if (!event.getProperty().toString().equals("[]")) {
+ getWindow().showNotification(
+ "Selected cities: " + event.getProperty());
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableActions.png b/src/com/vaadin/demo/sampler/features/table/75-TableActions.png
new file mode 100644
index 0000000000..dacd3aea86
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableActions.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableCellStyling.png b/src/com/vaadin/demo/sampler/features/table/75-TableCellStyling.png
new file mode 100644
index 0000000000..798ec20b4f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableCellStyling.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableColumnAlignment.png b/src/com/vaadin/demo/sampler/features/table/75-TableColumnAlignment.png
new file mode 100644
index 0000000000..87d6a18a51
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableColumnAlignment.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableColumnCollapsing.png b/src/com/vaadin/demo/sampler/features/table/75-TableColumnCollapsing.png
new file mode 100644
index 0000000000..b0922dc00b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableColumnCollapsing.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableColumnHeaders.png b/src/com/vaadin/demo/sampler/features/table/75-TableColumnHeaders.png
new file mode 100644
index 0000000000..b277610f8d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableColumnHeaders.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableColumnReordering.png b/src/com/vaadin/demo/sampler/features/table/75-TableColumnReordering.png
new file mode 100644
index 0000000000..6c689212cc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableColumnReordering.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableHeaderIcons.png b/src/com/vaadin/demo/sampler/features/table/75-TableHeaderIcons.png
new file mode 100644
index 0000000000..b277610f8d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableHeaderIcons.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableLazyLoading.png b/src/com/vaadin/demo/sampler/features/table/75-TableLazyLoading.png
new file mode 100644
index 0000000000..e5a294cf65
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableLazyLoading.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableMouseEvents.png b/src/com/vaadin/demo/sampler/features/table/75-TableMouseEvents.png
new file mode 100644
index 0000000000..798ec20b4f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableMouseEvents.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableRowHeaders.png b/src/com/vaadin/demo/sampler/features/table/75-TableRowHeaders.png
new file mode 100644
index 0000000000..b277610f8d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableRowHeaders.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableRowStyling.png b/src/com/vaadin/demo/sampler/features/table/75-TableRowStyling.png
new file mode 100644
index 0000000000..f523a049fe
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableRowStyling.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/75-TableSorting.png b/src/com/vaadin/demo/sampler/features/table/75-TableSorting.png
new file mode 100644
index 0000000000..4014d3aec7
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/75-TableSorting.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/table/TableActions.java b/src/com/vaadin/demo/sampler/features/table/TableActions.java
new file mode 100644
index 0000000000..3c08f9cb75
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableActions.java
@@ -0,0 +1,44 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableActions extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, context menu";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Actions can be added to each row, and are show in a"
+ + " context menu when right-clicking.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableCellStyling.java b/src/com/vaadin/demo/sampler/features/table/TableCellStyling.java
new file mode 100644
index 0000000000..4dd1a41218
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableCellStyling.java
@@ -0,0 +1,46 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableCellStyling extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, styling cells";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableStylingExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Individual cells can be styled in a Table by using a"
+ + " CellStyleGenerator. Regular CSS is used to create the"
+ + " actual style.<br/>Double click a first or last name to"
+ + " mark/unmark that cell.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableColumnAlignment.java b/src/com/vaadin/demo/sampler/features/table/TableColumnAlignment.java
new file mode 100644
index 0000000000..5ede6a9de5
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableColumnAlignment.java
@@ -0,0 +1,42 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableColumnAlignment extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, column alignment";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Columns can be aligned left (default), center or right.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableColumnCollapsing.java b/src/com/vaadin/demo/sampler/features/table/TableColumnCollapsing.java
new file mode 100644
index 0000000000..fdc21f8620
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableColumnCollapsing.java
@@ -0,0 +1,46 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableColumnCollapsing extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, column collapsing";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Columns can be 'collapsed', which means that it's not shown,"
+ + " but the user can make the column re-appear by using the"
+ + " menu in the upper right of the table.<br/>"
+ + " Columns can also be made invisible, in which case they can"
+ + " not be brought back by the user.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableColumnHeaders.java b/src/com/vaadin/demo/sampler/features/table/TableColumnHeaders.java
new file mode 100644
index 0000000000..aa4dc85ddd
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableColumnHeaders.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableColumnHeaders extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, column headers";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "A Table can have column headers, which support different modes"
+ + " with automatic or explicitly set caption and/or icon.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableColumnReordering.java b/src/com/vaadin/demo/sampler/features/table/TableColumnReordering.java
new file mode 100644
index 0000000000..7b01fedc78
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableColumnReordering.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableColumnReordering extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, column drag&drop";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "The columns can be rearranged with drag&drop - a feature"
+ + " which can be enabled or disabled.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableHeaderIcons.java b/src/com/vaadin/demo/sampler/features/table/TableHeaderIcons.java
new file mode 100644
index 0000000000..df12a44097
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableHeaderIcons.java
@@ -0,0 +1,44 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableHeaderIcons extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, icons in headers";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "A Table can have icons in the column- and rowheaders. "
+ + " The rowheader icon can come from a item property, or be"
+ + " explicitly set.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableLazyLoading.java b/src/com/vaadin/demo/sampler/features/table/TableLazyLoading.java
new file mode 100644
index 0000000000..a800451258
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableLazyLoading.java
@@ -0,0 +1,46 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableLazyLoading extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, lazy loading";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Table supports lazy-loading, which means that the content is"
+ + " loaded from the server only when needed. This allows the "
+ + " table to stay efficient even when scrolling hundreds of"
+ + " thousands of rows.<br/>Try scrolling a fair amount quickly!";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableMainFeaturesExample.java b/src/com/vaadin/demo/sampler/features/table/TableMainFeaturesExample.java
new file mode 100644
index 0000000000..3629f9e9ae
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableMainFeaturesExample.java
@@ -0,0 +1,150 @@
+package com.vaadin.demo.sampler.features.table;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.event.Action;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Table.CellStyleGenerator;
+
+public class TableMainFeaturesExample extends VerticalLayout {
+
+ Table table = new Table("ISO-3166 Country Codes and flags");
+
+ HashSet<Object> markedRows = new HashSet<Object>();
+
+ static final Action ACTION_MARK = new Action("Mark");
+ static final Action ACTION_UNMARK = new Action("Unmark");
+ static final Action ACTION_LOG = new Action("Save");
+ static final Action[] ACTIONS_UNMARKED = new Action[] { ACTION_MARK,
+ ACTION_LOG };
+ static final Action[] ACTIONS_MARKED = new Action[] { ACTION_UNMARK,
+ ACTION_LOG };
+
+ public TableMainFeaturesExample() {
+ addComponent(table);
+
+ // Label to indicate current selection
+ final Label selected = new Label("No selection");
+ addComponent(selected);
+
+ // set a style name, so we can style rows and cells
+ table.setStyleName("iso3166");
+
+ // size
+ table.setWidth("100%");
+ table.setPageLength(7);
+
+ // selectable
+ table.setSelectable(true);
+ table.setMultiSelect(true);
+ table.setImmediate(true); // react at once when something is selected
+
+ // connect data source
+ table.setContainerDataSource(ExampleUtil.getISO3166Container());
+
+ // turn on column reordering and collapsing
+ table.setColumnReorderingAllowed(true);
+ table.setColumnCollapsingAllowed(true);
+
+ // set column headers
+ table.setColumnHeaders(new String[] { "Country", "Code", "Icon file" });
+
+ // Icons for column headers
+ table.setColumnIcon(ExampleUtil.iso3166_PROPERTY_FLAG,
+ new ThemeResource("icons/action_save.gif"));
+ table.setColumnIcon(ExampleUtil.iso3166_PROPERTY_NAME,
+ new ThemeResource("icons/icon_get_world.gif"));
+ table.setColumnIcon(ExampleUtil.iso3166_PROPERTY_SHORT,
+ new ThemeResource("icons/page_code.gif"));
+
+ // Column alignment
+ table.setColumnAlignment(ExampleUtil.iso3166_PROPERTY_SHORT,
+ Table.ALIGN_CENTER);
+
+ // Column width
+ table.setColumnExpandRatio(ExampleUtil.iso3166_PROPERTY_NAME, 1);
+ table.setColumnWidth(ExampleUtil.iso3166_PROPERTY_SHORT, 70);
+
+ // Collapse one column - the user can make it visible again
+ try {
+ table.setColumnCollapsed(ExampleUtil.iso3166_PROPERTY_FLAG, true);
+ } catch (IllegalAccessException e) {
+ // Not critical, but strange
+ System.err.println(e);
+ }
+
+ // show row header w/ icon
+ table.setRowHeaderMode(Table.ROW_HEADER_MODE_ICON_ONLY);
+ table.setItemIconPropertyId(ExampleUtil.iso3166_PROPERTY_FLAG);
+
+ // Actions (a.k.a context menu)
+ table.addActionHandler(new Action.Handler() {
+ public Action[] getActions(Object target, Object sender) {
+ if (markedRows.contains(target)) {
+ return ACTIONS_MARKED;
+ } else {
+ return ACTIONS_UNMARKED;
+ }
+ }
+
+ public void handleAction(Action action, Object sender, Object target) {
+ if (ACTION_MARK.equals(action)) {
+ markedRows.add(target);
+ table.requestRepaint();
+ } else if (ACTION_UNMARK.equals(action)) {
+ markedRows.remove(target);
+ table.requestRepaint();
+ } else if (ACTION_LOG.equals(action)) {
+ Item item = table.getItem(target);
+ addComponent(new Label("Saved: "
+ + target
+ + ", "
+ + item.getItemProperty(
+ ExampleUtil.iso3166_PROPERTY_NAME)
+ .getValue()));
+ }
+
+ }
+
+ });
+
+ // style generator
+ table.setCellStyleGenerator(new CellStyleGenerator() {
+ public String getStyle(Object itemId, Object propertyId) {
+ if (propertyId == null) {
+ // no propertyId, styling row
+ return (markedRows.contains(itemId) ? "marked" : null);
+ } else if (ExampleUtil.iso3166_PROPERTY_NAME.equals(propertyId)) {
+ return "bold";
+ } else {
+ // no style
+ return null;
+ }
+
+ }
+
+ });
+
+ // listen for valueChange, a.k.a 'select' and update the label
+ table.addListener(new Table.ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ // in multiselect mode, a Set of itemIds is returned,
+ // in singleselect mode the itemId is returned directly
+ Set value = (Set) event.getProperty().getValue();
+ if (null == value || value.size() == 0) {
+ selected.setValue("No selection");
+ } else {
+ selected.setValue("Selected: " + table.getValue());
+ }
+ }
+ });
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableMouseEvents.java b/src/com/vaadin/demo/sampler/features/table/TableMouseEvents.java
new file mode 100644
index 0000000000..8cc57641aa
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableMouseEvents.java
@@ -0,0 +1,45 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableMouseEvents extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, mouse events";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableStylingExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "An ItemClickListener can be used to react to mouse click"
+ + " events. Different buttons, double click, and modifier keys"
+ + " can be detected.<br/>Double-click a first or last name to"
+ + " toggle it's marked state.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableRowHeaders.java b/src/com/vaadin/demo/sampler/features/table/TableRowHeaders.java
new file mode 100644
index 0000000000..1eb98dc871
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableRowHeaders.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableRowHeaders extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, row headers";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "A Table can have row headers, which support different modes"
+ + " with automatic or explicitly set caption and/or icon.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableRowStyling.java b/src/com/vaadin/demo/sampler/features/table/TableRowStyling.java
new file mode 100644
index 0000000000..af022f9813
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableRowStyling.java
@@ -0,0 +1,46 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableRowStyling extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, row styling";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableStylingExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Rows can be styled in a Table by using a CellStyleGenerator."
+ + " Regular CSS is used to create the actual style.<br/>Use the"
+ + " context menu (right-/ctrl-click) to apply a row style in"
+ + " the example.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableSorting.java b/src/com/vaadin/demo/sampler/features/table/TableSorting.java
new file mode 100644
index 0000000000..a812b9cf75
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableSorting.java
@@ -0,0 +1,45 @@
+package com.vaadin.demo.sampler.features.table;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Table;
+
+public class TableSorting extends Feature {
+
+ @Override
+ public String getName() {
+ return "Table, sorting";
+ }
+
+ @Override
+ public Component getExample() {
+ return new TableMainFeaturesExample();
+ }
+
+ @Override
+ public String getDescription() {
+ return "The Table columns can (optionally) be sorted by clicking the"
+ + " column header - a sort direction indicator will appear."
+ + " Clicking again will change the sorting direction.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Table.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Tables.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/table/TableStylingExample.java b/src/com/vaadin/demo/sampler/features/table/TableStylingExample.java
new file mode 100644
index 0000000000..afcd565ff7
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/table/TableStylingExample.java
@@ -0,0 +1,154 @@
+package com.vaadin.demo.sampler.features.table;
+
+import java.util.HashMap;
+import java.util.HashSet;
+
+import com.vaadin.data.Item;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.event.Action;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Table.CellStyleGenerator;
+
+public class TableStylingExample extends VerticalLayout {
+
+ Table table = new Table();
+
+ HashMap<Object, String> markedRows = new HashMap<Object, String>();
+ HashMap<Object, HashSet<Object>> markedCells = new HashMap<Object, HashSet<Object>>();
+
+ static final Action ACTION_RED = new Action("red");
+ static final Action ACTION_BLUE = new Action("blue");
+ static final Action ACTION_GREEN = new Action("green");
+ static final Action ACTION_NONE = new Action("none");
+ static final Action[] ACTIONS = new Action[] { ACTION_RED, ACTION_GREEN,
+ ACTION_BLUE, ACTION_NONE };
+
+ public TableStylingExample() {
+ setSpacing(true);
+
+ addComponent(table);
+
+ // set a style name, so we can style rows and cells
+ table.setStyleName("contacts");
+
+ // size
+ table.setWidth("100%");
+ table.setPageLength(7);
+
+ // connect data source
+ table.setContainerDataSource(ExampleUtil.getPersonContainer());
+
+ // Generate the email-link from firstname & lastname
+ table.addGeneratedColumn("Email", new Table.ColumnGenerator() {
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Item item = table.getItem(itemId);
+ String fn = (String) item.getItemProperty(
+ ExampleUtil.PERSON_PROPERTY_FIRSTNAME).getValue();
+ String ln = (String) item.getItemProperty(
+ ExampleUtil.PERSON_PROPERTY_LASTNAME).getValue();
+ String email = fn.toLowerCase() + "." + ln.toLowerCase()
+ + "@example.com";
+ // the Link -component:
+ Link emailLink = new Link(email, new ExternalResource("mailto:"
+ + email));
+ return emailLink;
+ }
+
+ });
+
+ // turn on column reordering and collapsing
+ table.setColumnReorderingAllowed(true);
+ table.setColumnCollapsingAllowed(true);
+
+ // Actions (a.k.a context menu)
+ table.addActionHandler(new Action.Handler() {
+ public Action[] getActions(Object target, Object sender) {
+ return ACTIONS;
+ }
+
+ public void handleAction(Action action, Object sender, Object target) {
+ markedRows.remove(target);
+ if (!ACTION_NONE.equals(action)) {
+ // we're using the cations caption as stylename as well:
+ markedRows.put(target, action.getCaption());
+ }
+ // this causes the CellStyleGenerator to return new styles,
+ // but table can't automatically know, we must tell it:
+ table.requestRepaint();
+ }
+
+ });
+
+ // style generator
+ table.setCellStyleGenerator(new CellStyleGenerator() {
+ public String getStyle(Object itemId, Object propertyId) {
+ if (propertyId == null) {
+ // no propertyId, styling row
+ return (markedRows.get(itemId));
+ } else if (propertyId.equals("Email")) {
+ // style the generated email column
+ return "email";
+ } else {
+ HashSet<Object> cells = markedCells.get(itemId);
+ if (cells != null && cells.contains(propertyId)) {
+ // marked cell
+ return "marked";
+ } else {
+ // no style
+ return null;
+ }
+ }
+
+ }
+
+ });
+
+ // toggle cell 'marked' styling when double-clicked
+ table.addListener(new ItemClickListener() {
+ public void itemClick(ItemClickEvent event) {
+ if (event.isDoubleClick()) {
+ Object itemId = event.getItemId();
+ Object propertyId = event.getPropertyId();
+ HashSet<Object> cells = markedCells.get(itemId);
+ if (cells == null) {
+ cells = new HashSet<Object>();
+ markedCells.put(itemId, cells);
+ }
+ if (cells.contains(propertyId)) {
+ // toggle marking off
+ cells.remove(propertyId);
+ } else {
+ // toggle marking on
+ cells.add(propertyId);
+ }
+ // this causes the CellStyleGenerator to return new styles,
+ // but table can't automatically know, we must tell it:
+ table.requestRepaint();
+ }
+ }
+ });
+
+ // Editing
+ // we don't want to update container before pressing 'save':
+ table.setWriteThrough(false);
+ // edit button
+ final Button editButton = new Button("Edit");
+ addComponent(editButton);
+ editButton.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ table.setEditable(!table.isEditable());
+ editButton.setCaption((table.isEditable() ? "Save" : "Edit"));
+ }
+ });
+ setComponentAlignment(editButton, "right");
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetDisabled.png b/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetDisabled.png
new file mode 100644
index 0000000000..ce99368151
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetDisabled.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetIcons.png b/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetIcons.png
new file mode 100644
index 0000000000..d7420ddc35
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetIcons.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetScrolling.png b/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetScrolling.png
new file mode 100644
index 0000000000..b62e084a9c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/75-TabSheetScrolling.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabled.java b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabled.java
new file mode 100644
index 0000000000..ad8a52cc83
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabled.java
@@ -0,0 +1,35 @@
+package com.vaadin.demo.sampler.features.tabsheets;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.TabSheet;
+
+public class TabSheetDisabled extends Feature {
+ @Override
+ public String getName() {
+ return "Tabsheet, disabled tabs";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Individual tabs can be enabled, disabled, hidden or visible.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TabSheet.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TabSheetIcons.class, TabSheetScrolling.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabledExample.java b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabledExample.java
new file mode 100644
index 0000000000..1491e57e85
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetDisabledExample.java
@@ -0,0 +1,90 @@
+package com.vaadin.demo.sampler.features.tabsheets;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
+import com.vaadin.ui.TabSheet.Tab;
+
+public class TabSheetDisabledExample extends VerticalLayout implements
+ TabSheet.SelectedTabChangeListener, Button.ClickListener {
+ private static final ThemeResource icon1 = new ThemeResource(
+ "icons/action_save.gif");
+ private static final ThemeResource icon2 = new ThemeResource(
+ "icons/comment_yellow.gif");
+ private static final ThemeResource icon3 = new ThemeResource(
+ "icons/icon_info.gif");
+
+ private TabSheet t;
+ private Button toggleEnabled;
+ private Button toggleVisible;
+ private VerticalLayout l1;
+ private VerticalLayout l2;
+ private VerticalLayout l3;
+ private Tab t1, t2, t3;
+
+ public TabSheetDisabledExample() {
+ setSpacing(true);
+
+ // Tab 1 content
+ l1 = new VerticalLayout();
+ l1.setMargin(true);
+ l1.addComponent(new Label("There are no previously saved actions."));
+ // Tab 2 content
+ l2 = new VerticalLayout();
+ l2.setMargin(true);
+ l2.addComponent(new Label("There are no saved notes."));
+ // Tab 3 content
+ l3 = new VerticalLayout();
+ l3.setMargin(true);
+ l3.addComponent(new Label("There are currently no issues."));
+
+ t = new TabSheet();
+ t.setHeight("200px");
+ t.setWidth("400px");
+ t1 = t.addTab(l1, "Saved actions", icon1);
+ t2 = t.addTab(l2, "Notes", icon2);
+ t3 = t.addTab(l3, "Issues", icon3);
+ t.addListener(this);
+
+ toggleEnabled = new Button("Disable 'Notes' tab");
+ toggleEnabled.addListener(this);
+
+ toggleVisible = new Button("Hide 'Issues' tab");
+ toggleVisible.addListener(this);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setSpacing(true);
+ hl.addComponent(toggleEnabled);
+ hl.addComponent(toggleVisible);
+
+ addComponent(t);
+ addComponent(hl);
+ }
+
+ public void selectedTabChange(SelectedTabChangeEvent event) {
+ String c = t.getTab(event.getTabSheet().getSelectedTab()).getCaption();
+ getWindow().showNotification("Selected tab: " + c);
+ }
+
+ public void buttonClick(ClickEvent event) {
+ if (toggleEnabled.equals(event.getButton())) {
+ // toggleEnabled clicked
+ t2.setEnabled(!t2.isEnabled());
+ toggleEnabled.setCaption((t2.isEnabled() ? "Disable" : "Enable")
+ + " 'Notes' tab");
+
+ } else {
+ // toggleVisible clicked
+ t3.setVisible(!t3.isVisible());
+ toggleVisible.setCaption((t3.isVisible() ? "Hide" : "Show")
+ + " 'Issues' tab");
+
+ }
+ t.requestRepaint();
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIcons.java b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIcons.java
new file mode 100644
index 0000000000..aa7a1d180c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIcons.java
@@ -0,0 +1,35 @@
+package com.vaadin.demo.sampler.features.tabsheets;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.TabSheet;
+
+public class TabSheetIcons extends Feature {
+ @Override
+ public String getName() {
+ return "Tabsheet with icons";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Each tab can have an Icon in addition to the caption.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TabSheet.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TabSheetScrolling.class, TabSheetDisabled.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIconsExample.java b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIconsExample.java
new file mode 100644
index 0000000000..5bbe5e8835
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetIconsExample.java
@@ -0,0 +1,52 @@
+package com.vaadin.demo.sampler.features.tabsheets;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
+
+public class TabSheetIconsExample extends VerticalLayout implements
+ TabSheet.SelectedTabChangeListener {
+
+ // Icons for the table
+ private static final ThemeResource icon1 = new ThemeResource(
+ "icons/action_save.gif");
+ private static final ThemeResource icon2 = new ThemeResource(
+ "icons/comment_yellow.gif");
+ private static final ThemeResource icon3 = new ThemeResource(
+ "icons/icon_info.gif");
+
+ private TabSheet t;
+
+ public TabSheetIconsExample() {
+ // Tab 1 content
+ VerticalLayout l1 = new VerticalLayout();
+ l1.setMargin(true);
+ l1.addComponent(new Label("There are no previously saved actions."));
+ // Tab 2 content
+ VerticalLayout l2 = new VerticalLayout();
+ l2.setMargin(true);
+ l2.addComponent(new Label("There are no saved notes."));
+ // Tab 3 content
+ VerticalLayout l3 = new VerticalLayout();
+ l3.setMargin(true);
+ l3.addComponent(new Label("There are currently no issues."));
+
+ t = new TabSheet();
+ t.setHeight("200px");
+ t.setWidth("400px");
+
+ t.addTab(l1, "Saved actions", icon1);
+ t.addTab(l2, "Notes", icon2);
+ t.addTab(l3, "Issues", icon3);
+ t.addListener(this);
+
+ addComponent(t);
+ }
+
+ public void selectedTabChange(SelectedTabChangeEvent event) {
+ String c = t.getTabCaption(event.getTabSheet().getSelectedTab());
+ getWindow().showNotification("Selected tab: " + c);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrolling.java b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrolling.java
new file mode 100644
index 0000000000..6fcae06bc2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrolling.java
@@ -0,0 +1,35 @@
+package com.vaadin.demo.sampler.features.tabsheets;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.TabSheet;
+
+public class TabSheetScrolling extends Feature {
+ @Override
+ public String getName() {
+ return "Tabsheet, scrolling tabs";
+ }
+
+ @Override
+ public String getDescription() {
+ return "If the tabs are to many to be shown at once, a scrolling control will appear automatically.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TabSheet.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TabSheetIcons.class, TabSheetDisabled.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrollingExample.java b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrollingExample.java
new file mode 100644
index 0000000000..f5e3627f10
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/tabsheets/TabSheetScrollingExample.java
@@ -0,0 +1,60 @@
+package com.vaadin.demo.sampler.features.tabsheets;
+
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
+
+public class TabSheetScrollingExample extends VerticalLayout implements
+ TabSheet.SelectedTabChangeListener {
+
+ private static final ThemeResource icon1 = new ThemeResource(
+ "icons/action_save.gif");
+ private static final ThemeResource icon2 = new ThemeResource(
+ "icons/comment_yellow.gif");
+ private static final ThemeResource icon3 = new ThemeResource(
+ "icons/icon_info.gif");
+
+ private TabSheet t;
+
+ public TabSheetScrollingExample() {
+ // Tab 1 content
+ VerticalLayout l1 = new VerticalLayout();
+ l1.setMargin(true);
+ l1.addComponent(new Label("There are no previously saved actions."));
+ // Tab 2 content
+ VerticalLayout l2 = new VerticalLayout();
+ l2.setMargin(true);
+ l2.addComponent(new Label("There are no saved notes."));
+ // Tab 3 content
+ VerticalLayout l3 = new VerticalLayout();
+ l3.setMargin(true);
+ l3.addComponent(new Label("There are currently no issues."));
+ // Tab 4 content
+ VerticalLayout l4 = new VerticalLayout();
+ l4.setMargin(true);
+ l4.addComponent(new Label("There are no comments."));
+ // Tab 5 content
+ VerticalLayout l5 = new VerticalLayout();
+ l5.setMargin(true);
+ l5.addComponent(new Label("There is no new feedback."));
+
+ t = new TabSheet();
+ t.setHeight("200px");
+ t.setWidth("400px");
+ t.addTab(l1, "Saved actions", icon1);
+ t.addTab(l2, "Notes", icon2);
+ t.addTab(l3, "Issues", icon3);
+ t.addTab(l4, "Comments", icon2);
+ t.addTab(l5, "Feedback", icon2);
+ t.addListener(this);
+
+ addComponent(t);
+ }
+
+ public void selectedTabChange(SelectedTabChangeEvent event) {
+ String c = t.getTabCaption(event.getTabSheet().getSelectedTab());
+ getWindow().showNotification("Selected tab: " + c);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/75-LabelPlain.png b/src/com/vaadin/demo/sampler/features/text/75-LabelPlain.png
new file mode 100644
index 0000000000..73393d2f3c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-LabelPlain.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/75-LabelPreformatted.png b/src/com/vaadin/demo/sampler/features/text/75-LabelPreformatted.png
new file mode 100644
index 0000000000..70dd443db9
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-LabelPreformatted.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/75-LabelRich.png b/src/com/vaadin/demo/sampler/features/text/75-LabelRich.png
new file mode 100644
index 0000000000..8b8689dc02
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-LabelRich.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/75-RichTextEditor.png b/src/com/vaadin/demo/sampler/features/text/75-RichTextEditor.png
new file mode 100644
index 0000000000..022724b571
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-RichTextEditor.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/75-TextArea.png b/src/com/vaadin/demo/sampler/features/text/75-TextArea.png
new file mode 100644
index 0000000000..72497f104c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-TextArea.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/75-TextFieldInputPrompt.png b/src/com/vaadin/demo/sampler/features/text/75-TextFieldInputPrompt.png
new file mode 100644
index 0000000000..dc7fbb38f9
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-TextFieldInputPrompt.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/75-TextFieldSecret.png b/src/com/vaadin/demo/sampler/features/text/75-TextFieldSecret.png
new file mode 100644
index 0000000000..929c79e05a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-TextFieldSecret.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/75-TextFieldSingle.png b/src/com/vaadin/demo/sampler/features/text/75-TextFieldSingle.png
new file mode 100644
index 0000000000..5df731e6d3
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/75-TextFieldSingle.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/text/LabelPlain.java b/src/com/vaadin/demo/sampler/features/text/LabelPlain.java
new file mode 100644
index 0000000000..b30dc69005
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/LabelPlain.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Label;
+
+public class LabelPlain extends Feature {
+ @Override
+ public String getName() {
+ return "Label, plain text";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example the content mode is set to"
+ + " CONTENT_TEXT, meaning that the label will contain"
+ + " only plain text.";
+
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Label.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LabelPreformatted.class, LabelRich.class,
+ TextFieldSingle.class, TextArea.class, RichTextEditor.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/LabelPlainExample.java b/src/com/vaadin/demo/sampler/features/text/LabelPlainExample.java
new file mode 100644
index 0000000000..f96df7af68
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/LabelPlainExample.java
@@ -0,0 +1,20 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+
+public class LabelPlainExample extends VerticalLayout {
+
+ public LabelPlainExample() {
+ setSpacing(true);
+
+ Label plainText = new Label("This is an example of a Label"
+ + " component. The content mode of this label is set"
+ + " to CONTENT_TEXT. This means that it will display"
+ + " the content text as is. HTML and XML special characters"
+ + " (<,>,&) are escaped properly to allow displaying them.");
+ plainText.setContentMode(Label.CONTENT_TEXT);
+
+ addComponent(plainText);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/LabelPreformatted.java b/src/com/vaadin/demo/sampler/features/text/LabelPreformatted.java
new file mode 100644
index 0000000000..339a251583
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/LabelPreformatted.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Label;
+
+public class LabelPreformatted extends Feature {
+ @Override
+ public String getName() {
+ return "Label, preformatted";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example the content mode is set to"
+ + " CONTENT_PREFORMATTED. The text for this content type"
+ + " is by default rendered with fixed-width font. Line breaks"
+ + " can be inserted with \\n and tabulator characters with \\t.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Label.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LabelPlain.class, LabelRich.class,
+ TextFieldSingle.class, TextArea.class, RichTextEditor.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/LabelPreformattedExample.java b/src/com/vaadin/demo/sampler/features/text/LabelPreformattedExample.java
new file mode 100644
index 0000000000..f9dfb597ed
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/LabelPreformattedExample.java
@@ -0,0 +1,25 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+
+public class LabelPreformattedExample extends VerticalLayout {
+
+ public LabelPreformattedExample() {
+ setSpacing(true);
+
+ Label preformattedText = new Label(
+ "This is an example of a Label component.\n"
+ + "\nThe content mode of this label is set"
+ + "\nto CONTENT_PREFORMATTED. This means"
+ + "\nthat it will display the content text"
+ + "\nusing a fixed-width font. You also have"
+ + "\nto insert the line breaks yourself.\n"
+ + "\n\tHTML and XML special characters"
+ + "\n\t(<,>,&) are escaped properly to"
+ + "\n\tallow displaying them.");
+ preformattedText.setContentMode(Label.CONTENT_PREFORMATTED);
+
+ addComponent(preformattedText);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/LabelRich.java b/src/com/vaadin/demo/sampler/features/text/LabelRich.java
new file mode 100644
index 0000000000..40ac46f175
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/LabelRich.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Label;
+
+public class LabelRich extends Feature {
+ @Override
+ public String getName() {
+ return "Label, rich text";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example the content mode is set to"
+ + " CONTENT_XHTML. This content mode assumes that the"
+ + " content set to the label will be valid XHTML.<br/>"
+ + "Click the <i>Edit</i> button to edit the label content.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Label.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { LabelPlain.class, LabelPreformatted.class,
+ RichTextEditor.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/LabelRichExample.java b/src/com/vaadin/demo/sampler/features/text/LabelRichExample.java
new file mode 100644
index 0000000000..289e916a8d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/LabelRichExample.java
@@ -0,0 +1,48 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+public class LabelRichExample extends VerticalLayout implements ClickListener {
+
+ private Button b;
+ private Label richText;
+
+ private final RichTextArea editor = new RichTextArea();
+
+ public LabelRichExample() {
+ setSpacing(true);
+ setSizeUndefined(); // let layout grow with content
+
+ richText = new Label(
+ "<h1>Rich text example</h1>"
+ + "<p>The <b>quick</b> brown fox jumps <sup>over</sup> the <b>lazy</b> dog.</p>"
+ + "<p>This text can be edited with the <i>Edit</i> -button</p>");
+ richText.setContentMode(Label.CONTENT_XHTML);
+ richText.setSizeUndefined();
+
+ addComponent(richText);
+
+ b = new Button("Edit");
+ b.addListener(this);
+ addComponent(b);
+ setComponentAlignment(b, "right");
+ }
+
+ public void buttonClick(ClickEvent event) {
+ if (getComponentIterator().next() == richText) {
+ editor.setValue(richText.getValue());
+ replaceComponent(richText, editor);
+ b.setCaption("Apply");
+ } else {
+ richText.setValue(editor.getValue());
+ replaceComponent(editor, richText);
+ b.setCaption("Edit");
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/RichTextEditor.java b/src/com/vaadin/demo/sampler/features/text/RichTextEditor.java
new file mode 100644
index 0000000000..2ef5661329
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/RichTextEditor.java
@@ -0,0 +1,42 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.RichTextArea;
+
+public class RichTextEditor extends Feature {
+ @Override
+ public String getName() {
+ return "Rich text area";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The RichTextArea allows 'rich' formatting of the input.<br/>"
+ + "Click the <i>Edit</i> button to edit the label content"
+ + " with the RichTextArea.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(RichTextArea.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TextArea.class, LabelRich.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Component getExample() {
+ return new LabelRichExample();
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextArea.java b/src/com/vaadin/demo/sampler/features/text/TextArea.java
new file mode 100644
index 0000000000..3bb731e4d3
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextArea.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.TextField;
+
+public class TextArea extends Feature {
+ @Override
+ public String getName() {
+ return "Text area";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A text field can be configured to allow multiple lines of input."
+ + "<br>The amount of columns and lines can be set, and both are set here to"
+ + " 20 characters. Note that this only affects the width and height of the"
+ + " component, not the allowed length of input.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TextField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { RichTextEditor.class, TextFieldSingle.class,
+ FeatureSet.Texts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextAreaExample.java b/src/com/vaadin/demo/sampler/features/text/TextAreaExample.java
new file mode 100644
index 0000000000..c6ca5fe181
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextAreaExample.java
@@ -0,0 +1,49 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+
+public class TextAreaExample extends HorizontalLayout implements
+ Property.ValueChangeListener {
+
+ private static final String initialText = "The quick brown fox jumps over the lazy dog.";
+
+ private Label plainText;
+ private final TextField editor;
+
+ public TextAreaExample() {
+ setSpacing(true);
+
+ editor = new TextField("", initialText);
+ editor.setRows(20); // this will make it an 'area', i.e multiline
+ editor.setColumns(20);
+ editor.addListener(this);
+ editor.setImmediate(true);
+ addComponent(editor);
+
+ // the TextArea is immediate, and it's valueCahnge updates the Label,
+ // so this button actually does nothing
+ addComponent(new Button(">"));
+
+ plainText = new Label(initialText);
+ plainText.setContentMode(Label.CONTENT_XHTML);
+ addComponent(plainText);
+ }
+
+ /*
+ * Catch the valuechange event of the textfield and update the value of the
+ * label component
+ */
+ public void valueChange(ValueChangeEvent event) {
+ String text = (String) editor.getValue();
+ if (text != null) {
+ // replace newline with BR, because we're using Label.CONTENT_XHTML
+ text = text.replaceAll("\n", "<br/>");
+ }
+ plainText.setValue(text);
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextFieldInputPrompt.java b/src/com/vaadin/demo/sampler/features/text/TextFieldInputPrompt.java
new file mode 100644
index 0000000000..a7da1c61d7
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextFieldInputPrompt.java
@@ -0,0 +1,47 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.selects.ComboBoxInputPrompt;
+import com.vaadin.demo.sampler.features.selects.ComboBoxNewItems;
+import com.vaadin.ui.TextField;
+
+public class TextFieldInputPrompt extends Feature {
+ @Override
+ public String getName() {
+ return "Text field with input prompt";
+ }
+
+ @Override
+ public String getDescription() {
+ return " The TextField can have an <i>input prompt</i> - a textual hint that is shown within"
+ + " the field when the field is otherwise empty.<br/>"
+ + " You can use an input prompt instead of a caption to save"
+ + " space, but only do so if the function of the TextField is"
+ + " still clear when a value has been entered and the prompt is no"
+ + " longer visible.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TextField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ // TODO update CB -ref to 'suggest' pattern, when available
+ return new Class[] { TextFieldSingle.class, TextFieldSecret.class,
+ ComboBoxInputPrompt.class, ComboBoxNewItems.class,
+ FeatureSet.Texts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] { new NamedExternalResource(
+ "UI Patterns, Input Prompt",
+ "http://ui-patterns.com/pattern/InputPrompt") };
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextFieldInputPromptExample.java b/src/com/vaadin/demo/sampler/features/text/TextFieldInputPromptExample.java
new file mode 100644
index 0000000000..9f3d40b445
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextFieldInputPromptExample.java
@@ -0,0 +1,49 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class TextFieldInputPromptExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ public TextFieldInputPromptExample() {
+ // add som 'air' to the layout
+ setSpacing(true);
+ setMargin(true);
+
+ // Username field + input prompt
+ TextField username = new TextField();
+ username.setInputPrompt("Username");
+ // configure & add to layout
+ username.setImmediate(true);
+ username.addListener(this);
+ addComponent(username);
+
+ // Password field + input prompt
+ TextField password = new TextField();
+ password.setInputPrompt("Password");
+ // configure & add to layout
+ password.setSecret(true);
+ password.setImmediate(true);
+ password.addListener(this);
+ addComponent(password);
+
+ // Comment field + input prompt
+ TextField comment = new TextField();
+ comment.setInputPrompt("Comment");
+ // configure & add to layout
+ comment.setRows(3);
+ comment.setImmediate(true);
+ comment.addListener(this);
+ addComponent(comment);
+
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ getWindow().showNotification("Received " + event.getProperty());
+
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextFieldSecret.java b/src/com/vaadin/demo/sampler/features/text/TextFieldSecret.java
new file mode 100644
index 0000000000..b40daafedc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextFieldSecret.java
@@ -0,0 +1,41 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.selects.ComboBoxNewItems;
+import com.vaadin.ui.TextField;
+
+public class TextFieldSecret extends Feature {
+ @Override
+ public String getName() {
+ return "Text field, secret (password)";
+ }
+
+ @Override
+ public String getDescription() {
+ return "For sensitive data input, such as passwords, the text field can"
+ + " also be set into secret mode where the input will not be"
+ + " echoed to display.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TextField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ // TODO update CB -ref to 'suggest' pattern, when available
+ return new Class[] { TextFieldSingle.class, ComboBoxNewItems.class,
+ FeatureSet.Texts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextFieldSecretExample.java b/src/com/vaadin/demo/sampler/features/text/TextFieldSecretExample.java
new file mode 100644
index 0000000000..f0fee03346
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextFieldSecretExample.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class TextFieldSecretExample extends VerticalLayout {
+
+ private final TextField username;
+ private final TextField password;
+
+ public TextFieldSecretExample() {
+ setSizeUndefined(); // let content 'push' size
+ setSpacing(true);
+
+ // Username
+ username = new TextField("Username");
+ addComponent(username);
+
+ // Password
+ password = new TextField("Password");
+ password.setSecret(true);
+ addComponent(password);
+
+ // Login button
+ Button loginButton = new Button("Login", new Button.ClickListener() {
+ // inline click listener
+ public void buttonClick(ClickEvent event) {
+ getWindow().showNotification(
+ "User: " + username.getValue() + " Password: "
+ + password.getValue());
+
+ }
+ });
+ addComponent(loginButton);
+ setComponentAlignment(loginButton, "right");
+
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextFieldSingle.java b/src/com/vaadin/demo/sampler/features/text/TextFieldSingle.java
new file mode 100644
index 0000000000..15aa90de1c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextFieldSingle.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.features.selects.ComboBoxNewItems;
+import com.vaadin.ui.TextField;
+
+public class TextFieldSingle extends Feature {
+ @Override
+ public String getName() {
+ return "Text field";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A single-line TextField is a fundamental UI building blocks"
+ + " with numerous uses.<br/>"
+ + "If the input would benefit from remembering previous values,"
+ + " you might want to consider using a ComboBox it it's "
+ + " 'suggesting mode' instead.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(TextField.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ // TODO update CB -ref to 'suggest' pattern, when available
+ return new Class[] { TextFieldSecret.class, ComboBoxNewItems.class,
+ FeatureSet.Texts.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/text/TextFieldSingleExample.java b/src/com/vaadin/demo/sampler/features/text/TextFieldSingleExample.java
new file mode 100644
index 0000000000..53b20db7ed
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/text/TextFieldSingleExample.java
@@ -0,0 +1,31 @@
+package com.vaadin.demo.sampler.features.text;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class TextFieldSingleExample extends VerticalLayout implements
+ Property.ValueChangeListener {
+
+ private final TextField editor = new TextField("Echo this:");
+
+ public TextFieldSingleExample() {
+ setSpacing(true);
+
+ editor.addListener(this);
+ editor.setImmediate(true);
+ // editor.setColumns(5); // guarantees that at least 5 chars fit
+
+ addComponent(editor);
+ }
+
+ /*
+ * Catch the valuechange event of the textfield and update the value of the
+ * label component
+ */
+ public void valueChange(ValueChangeEvent event) {
+ // Show the new value we received
+ getWindow().showNotification((String) editor.getValue());
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/trees/75-TreeActions.png b/src/com/vaadin/demo/sampler/features/trees/75-TreeActions.png
new file mode 100644
index 0000000000..7b68dee674
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/75-TreeActions.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/trees/75-TreeMouseEvents.png b/src/com/vaadin/demo/sampler/features/trees/75-TreeMouseEvents.png
new file mode 100644
index 0000000000..3f22f288d1
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/75-TreeMouseEvents.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/trees/75-TreeMultiSelect.png b/src/com/vaadin/demo/sampler/features/trees/75-TreeMultiSelect.png
new file mode 100644
index 0000000000..3b0b250c90
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/75-TreeMultiSelect.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/trees/75-TreeSingleSelect.png b/src/com/vaadin/demo/sampler/features/trees/75-TreeSingleSelect.png
new file mode 100644
index 0000000000..03ef1eae76
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/75-TreeSingleSelect.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/trees/TreeActions.java b/src/com/vaadin/demo/sampler/features/trees/TreeActions.java
new file mode 100644
index 0000000000..3d270e265f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/TreeActions.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.sampler.features.trees;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Tree;
+
+public class TreeActions extends Feature {
+ @Override
+ public String getName() {
+ return "Tree, context menu";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, actions have been attached to"
+ + " the tree component. Try clicking the secondary mouse"
+ + " button on an item in the tree.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Tree.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TreeSingleSelect.class, TreeMultiSelect.class,
+ TreeMouseEvents.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Component getExample() {
+ return new TreeSingleSelectExample();
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/trees/TreeMouseEvents.java b/src/com/vaadin/demo/sampler/features/trees/TreeMouseEvents.java
new file mode 100644
index 0000000000..261f72112f
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/TreeMouseEvents.java
@@ -0,0 +1,41 @@
+package com.vaadin.demo.sampler.features.trees;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Tree;
+
+public class TreeMouseEvents extends Feature {
+ @Override
+ public String getName() {
+ return "Tree, mouse events";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, selecting items from the tree"
+ + " is disabled. Instead, another method of selection"
+ + " is used. Using the ItemClickEvent, we can update the"
+ + " label showing the selection."
+ + "<br>Try to click your left, right and middle mouse"
+ + " buttons on the tree items. Any modifier keys will"
+ + " also be detected.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Tree.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TreeSingleSelect.class, TreeMultiSelect.class,
+ TreeActions.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/trees/TreeMouseEventsExample.java b/src/com/vaadin/demo/sampler/features/trees/TreeMouseEventsExample.java
new file mode 100644
index 0000000000..48d560447d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/TreeMouseEventsExample.java
@@ -0,0 +1,99 @@
+package com.vaadin.demo.sampler.features.trees;
+
+import com.vaadin.data.Item;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.VerticalLayout;
+
+public class TreeMouseEventsExample extends VerticalLayout implements
+ ItemClickListener {
+
+ private Tree t;
+ private int itemId;
+
+ public TreeMouseEventsExample() {
+ setSpacing(true);
+
+ // Create new Tree object using a hierarchical container from
+ // ExampleUtil class
+ t = new Tree("Hardware Inventory", ExampleUtil.getHardwareContainer());
+
+ // Add ItemClickListener to the tree
+ t.addListener(this);
+
+ t.setImmediate(true);
+
+ // Set tree to show the 'name' property as caption for items
+ t.setItemCaptionPropertyId(ExampleUtil.hw_PROPERTY_NAME);
+ t.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+
+ // Starting itemId # for new items
+ itemId = t.getContainerDataSource().size();
+
+ // Expand whole tree
+ for (int i = 0; i < itemId; i++) {
+ t.expandItemsRecursively(i);
+ }
+
+ // Disallow selecting items from the tree
+ t.setSelectable(false);
+
+ addComponent(t);
+ }
+
+ public void itemClick(ItemClickEvent event) {
+ // Indicate which modifier keys are pressed
+ String modifiers = "";
+ if (event.isAltKey()) {
+ modifiers += "Alt ";
+ }
+ if (event.isCtrlKey()) {
+ modifiers += "Ctrl ";
+ }
+ if (event.isMetaKey()) {
+ modifiers += "Meta ";
+ }
+ if (event.isShiftKey()) {
+ modifiers += "Shift ";
+ }
+ if (modifiers.length() > 0) {
+ modifiers = "Modifiers: " + modifiers;
+ } else {
+ modifiers = "Modifiers: none";
+ }
+ switch (event.getButton()) {
+ case ItemClickEvent.BUTTON_LEFT:
+ // Left button click updates the 'selected' Label
+ getWindow().showNotification("Selected item: " + event.getItem(),
+ modifiers);
+ break;
+ case ItemClickEvent.BUTTON_MIDDLE:
+ // Middle button click removes the item
+ Object parent = t.getParent(event.getItemId());
+ getWindow().showNotification("Removed item: " + event.getItem(),
+ modifiers);
+ t.removeItem(event.getItemId());
+ if (parent != null && t.getChildren(parent).size() == 0) {
+ t.setChildrenAllowed(parent, false);
+ }
+ break;
+ case ItemClickEvent.BUTTON_RIGHT:
+ // Right button click creates a new child item
+ getWindow().showNotification("Added item: New Item # " + itemId,
+ modifiers);
+ t.setChildrenAllowed(event.getItemId(), true);
+ Item i = t.addItem(itemId);
+ t.setChildrenAllowed(itemId, false);
+ String newItemName = "New Item # " + itemId;
+ i.getItemProperty(ExampleUtil.hw_PROPERTY_NAME).setValue(
+ newItemName);
+ t.setParent(itemId, event.getItemId());
+ t.expandItem(event.getItemId());
+ itemId++;
+ break;
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/trees/TreeMultiSelect.java b/src/com/vaadin/demo/sampler/features/trees/TreeMultiSelect.java
new file mode 100644
index 0000000000..c83729b29b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/TreeMultiSelect.java
@@ -0,0 +1,36 @@
+package com.vaadin.demo.sampler.features.trees;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Tree;
+
+public class TreeMultiSelect extends Feature {
+ @Override
+ public String getName() {
+ return "Tree, multiple selections";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, you can select multiple tree nodes"
+ + " and delete the selected items. Click a selected item again to de-select it.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Tree.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TreeSingleSelect.class, TreeActions.class,
+ TreeMouseEvents.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/trees/TreeMultiSelectExample.java b/src/com/vaadin/demo/sampler/features/trees/TreeMultiSelectExample.java
new file mode 100644
index 0000000000..e97111ad85
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/TreeMultiSelectExample.java
@@ -0,0 +1,110 @@
+package com.vaadin.demo.sampler.features.trees;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.event.Action;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class TreeMultiSelectExample extends VerticalLayout implements
+ Action.Handler {
+
+ private static final Action ACTION_ADD = new Action("Add child item");
+ private static final Action ACTION_DELETE = new Action("Delete");
+ private static final Action[] ACTIONS = new Action[] { ACTION_ADD,
+ ACTION_DELETE };
+
+ private Tree tree;
+ private Button deleteButton;
+
+ public TreeMultiSelectExample() {
+ setSpacing(true);
+
+ // Create new Tree object using a hierarchical container from
+ // ExampleUtil class
+ tree = new Tree("Hardware Inventory", ExampleUtil
+ .getHardwareContainer());
+ // Set multiselect mode
+ tree.setMultiSelect(true);
+ tree.setImmediate(true);
+ tree.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ Tree t = (Tree) event.getProperty();
+ // enable if something is selected, returns a set
+ deleteButton.setEnabled(t.getValue() != null
+ && ((Set) t.getValue()).size() > 0);
+ }
+ });
+
+ // Add Actionhandler
+ tree.addActionHandler(this);
+
+ // Set tree to show the 'name' property as caption for items
+ tree.setItemCaptionPropertyId(ExampleUtil.hw_PROPERTY_NAME);
+ tree.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+
+ // Expand whole tree
+ for (Iterator it = tree.rootItemIds().iterator(); it.hasNext();) {
+ tree.expandItemsRecursively(it.next());
+ }
+
+ // Create the 'delete button', inline click-listener
+ deleteButton = new Button("Delete", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ // Delete all the selected objects
+ Object[] toDelete = ((Set<Object>) tree.getValue()).toArray();
+ for (int i = 0; i < toDelete.length; i++) {
+ handleAction(ACTION_DELETE, tree, toDelete[i]);
+ }
+ }
+ });
+ deleteButton.setEnabled(false);
+
+ addComponent(deleteButton);
+ addComponent(tree);
+
+ }
+
+ /*
+ * Returns the set of available actions
+ */
+ public Action[] getActions(Object target, Object sender) {
+ return ACTIONS;
+ }
+
+ /*
+ * Handle actions
+ */
+ public void handleAction(Action action, Object sender, Object target) {
+ if (action == ACTION_ADD) {
+ // Allow children for the target item
+ tree.setChildrenAllowed(target, true);
+
+ // Create new item, disallow children, add name, set parent
+ Object itemId = tree.addItem();
+ tree.setChildrenAllowed(itemId, false);
+ String newItemName = "New Item # " + itemId;
+ Item item = tree.getItem(itemId);
+ item.getItemProperty(ExampleUtil.hw_PROPERTY_NAME).setValue(
+ newItemName);
+ tree.setParent(itemId, target);
+ tree.expandItem(target);
+ } else if (action == ACTION_DELETE) {
+ Object parent = tree.getParent(target);
+ tree.removeItem(target);
+ // If the deleted object's parent has no more children, set it's
+ // childrenallowed property to false
+ if (parent != null && tree.getChildren(parent).size() == 0) {
+ tree.setChildrenAllowed(parent, false);
+ }
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/trees/TreeSingleSelect.java b/src/com/vaadin/demo/sampler/features/trees/TreeSingleSelect.java
new file mode 100644
index 0000000000..d25950cdbc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/TreeSingleSelect.java
@@ -0,0 +1,35 @@
+package com.vaadin.demo.sampler.features.trees;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Tree;
+
+public class TreeSingleSelect extends Feature {
+ @Override
+ public String getName() {
+ return "Tree, single selection";
+ }
+
+ @Override
+ public String getDescription() {
+ return "In this example, you can select any single tree node"
+ + " and modify its 'name' property. Click again to de-select.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Tree.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { TreeMultiSelect.class, TreeActions.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/trees/TreeSingleSelectExample.java b/src/com/vaadin/demo/sampler/features/trees/TreeSingleSelectExample.java
new file mode 100644
index 0000000000..0bbeacf921
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/trees/TreeSingleSelectExample.java
@@ -0,0 +1,133 @@
+package com.vaadin.demo.sampler.features.trees;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.demo.sampler.ExampleUtil;
+import com.vaadin.event.Action;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class TreeSingleSelectExample extends HorizontalLayout implements
+ Property.ValueChangeListener, Button.ClickListener, Action.Handler {
+
+ // Actions for the context menu
+ private static final Action ACTION_ADD = new Action("Add child item");
+ private static final Action ACTION_DELETE = new Action("Delete");
+ private static final Action[] ACTIONS = new Action[] { ACTION_ADD,
+ ACTION_DELETE };
+
+ private Tree tree;
+
+ HorizontalLayout editBar;
+ private TextField editor;
+ private Button change;
+
+ public TreeSingleSelectExample() {
+ setSpacing(true);
+
+ // Create the Tree,a dd to layout
+ tree = new Tree("Hardware Inventory");
+ addComponent(tree);
+
+ // Contents from a (prefilled example) hierarchical container:
+ tree.setContainerDataSource(ExampleUtil.getHardwareContainer());
+
+ // Add Valuechangelistener and Actionhandler
+ tree.addListener(this);
+
+ // Add actions (context menu)
+ tree.addActionHandler(this);
+
+ // Cause valueChange immediately when the user selects
+ tree.setImmediate(true);
+
+ // Set tree to show the 'name' property as caption for items
+ tree.setItemCaptionPropertyId(ExampleUtil.hw_PROPERTY_NAME);
+ tree.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+
+ // Expand whole tree
+ for (Object id : tree.rootItemIds()) {
+ tree.expandItemsRecursively(id);
+ }
+
+ // Create the 'editor bar' (textfield and button in a horizontallayout)
+ editBar = new HorizontalLayout();
+ editBar.setMargin(false, false, false, true);
+ editBar.setEnabled(false);
+ addComponent(editBar);
+ // textfield
+ editor = new TextField("Item name");
+ editor.setImmediate(true);
+ editBar.addComponent(editor);
+ // apply-button
+ change = new Button("Apply", this, "buttonClick");
+ editBar.addComponent(change);
+ editBar.setComponentAlignment(change, "bottom");
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ if (event.getProperty().getValue() != null) {
+ // If something is selected from the tree, get it's 'name' and
+ // insert it into the textfield
+ editor.setValue(tree.getItem(event.getProperty().getValue())
+ .getItemProperty(ExampleUtil.hw_PROPERTY_NAME));
+ editor.requestRepaint();
+ editBar.setEnabled(true);
+ } else {
+ editor.setValue("");
+ editBar.setEnabled(false);
+ }
+ }
+
+ public void buttonClick(ClickEvent event) {
+ // If the edited value contains something, set it to be the item's new
+ // 'name' property
+ if (!editor.getValue().equals("")) {
+ Item item = tree.getItem(tree.getValue());
+ Property name = item.getItemProperty(ExampleUtil.hw_PROPERTY_NAME);
+ name.setValue(editor.getValue());
+ }
+ }
+
+ /*
+ * Returns the set of available actions
+ */
+ public Action[] getActions(Object target, Object sender) {
+ return ACTIONS;
+ }
+
+ /*
+ * Handle actions
+ */
+ public void handleAction(Action action, Object sender, Object target) {
+ if (action == ACTION_ADD) {
+ // Allow children for the target item, and expand it
+ tree.setChildrenAllowed(target, true);
+ tree.expandItem(target);
+
+ // Create new item, set parent, disallow children (= leaf node)
+ Object itemId = tree.addItem();
+ tree.setParent(itemId, target);
+ tree.setChildrenAllowed(itemId, false);
+
+ // Set the name for this item (we use it as item caption)
+ Item item = tree.getItem(itemId);
+ Property name = item.getItemProperty(ExampleUtil.hw_PROPERTY_NAME);
+ name.setValue("New Item");
+
+ } else if (action == ACTION_DELETE) {
+ Object parent = tree.getParent(target);
+ tree.removeItem(target);
+ // If the deleted object's parent has no more children, set it's
+ // childrenallowed property to false (= leaf node)
+ if (parent != null && tree.getChildren(parent).size() == 0) {
+ tree.setChildrenAllowed(parent, false);
+ }
+ }
+ }
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/75-NativeWindow.png b/src/com/vaadin/demo/sampler/features/windows/75-NativeWindow.png
new file mode 100644
index 0000000000..14981b1836
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/75-NativeWindow.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/windows/75-Subwindow.png b/src/com/vaadin/demo/sampler/features/windows/75-Subwindow.png
new file mode 100644
index 0000000000..bd92cc04e8
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/75-Subwindow.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/windows/75-SubwindowAutoSized.png b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowAutoSized.png
new file mode 100644
index 0000000000..2752d2f581
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowAutoSized.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/windows/75-SubwindowClose.png b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowClose.png
new file mode 100644
index 0000000000..a76e9ba0b2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowClose.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/windows/75-SubwindowModal.png b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowModal.png
new file mode 100644
index 0000000000..0eb9cfe0fd
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowModal.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/windows/75-SubwindowPositioned.png b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowPositioned.png
new file mode 100644
index 0000000000..c3e0d5f0a3
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowPositioned.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/windows/75-SubwindowSized.png b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowSized.png
new file mode 100644
index 0000000000..c918d84063
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/75-SubwindowSized.png
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/features/windows/NativeWindow.java b/src/com/vaadin/demo/sampler/features/windows/NativeWindow.java
new file mode 100644
index 0000000000..0d030945b5
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/NativeWindow.java
@@ -0,0 +1,45 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.demo.sampler.FeatureSet.Links;
+import com.vaadin.demo.sampler.FeatureSet.Windows;
+import com.vaadin.ui.Window;
+
+public class NativeWindow extends Feature {
+
+ @Override
+ public String getName() {
+ return "Native window";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A <i>NativeWindow</i> is a separate browser window, which"
+ + " looks and works just like the main window.<br/>"
+ + " There are multiple ways to make native windows; you can"
+ + " override Application.getWindow() (recommended in any case)"
+ + " but you can also use Application.addWindow() - the added"
+ + " window will be available from a separate URL (which is"
+ + " based on the window name.)<br/> When you view Sampler in"
+ + " a new window, the getWindow() method is used, this example"
+ + " also uses addWindow().";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { Subwindow.class, Links.class, Windows.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/NativeWindowExample.java b/src/com/vaadin/demo/sampler/features/windows/NativeWindowExample.java
new file mode 100644
index 0000000000..b1b2933f1d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/NativeWindowExample.java
@@ -0,0 +1,83 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import java.util.Date;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class NativeWindowExample extends VerticalLayout {
+
+ public NativeWindowExample() {
+ setSpacing(true);
+
+ // Add a button for opening the window
+ Button open = new Button("Open native window",
+ new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ Window window = new NativeWindow();
+ // Add the window to the application
+ getApplication().addWindow(window);
+
+ // Get the URL for the window, and open that in a new
+ // browser window, in this case in a small window.
+ getWindow().open(new ExternalResource(window.getURL()), // URL
+ "_blank", // window name
+ 500, // width
+ 200, // weight
+ Window.BORDER_NONE // decorations
+ );
+ }
+ });
+ addComponent(open);
+
+ // Add a link for opening sampler in a new window; this will cause
+ // Sampler's getWindow() to create a new Window.
+ Link openSampler = new Link("Open Sampler in a new window",
+ new ExternalResource("#"), // URL
+ "_blank", // window name
+ 700, // width
+ 500, // height
+ Link.TARGET_BORDER_NONE // decorations
+ );
+ addComponent(openSampler);
+
+ }
+
+ /*
+ * We'll be instantiating the same window multiple times, so we'll make an
+ * inner class for separation. You could of course just create a new
+ * Window() and addCompoent to that instead.
+ */
+ class NativeWindow extends Window {
+ NativeWindow() {
+ // Configure the layout
+ VerticalLayout layout = (VerticalLayout) getLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+
+ // Add some content; a label and a close-button
+ Label message = new Label("This is a native window, created at "
+ + new Date());
+ addComponent(message);
+
+ // It's a good idea to remove the window when it's closed (also
+ // when the browser window 'x' is used), unless you explicitly
+ // want the window to persist (if it's not removed from the
+ // application, it can still be retrieved from it's URL.
+ addListener(new CloseListener() {
+ public void windowClose(CloseEvent e) {
+ // remove from application
+ getApplication().removeWindow(NativeWindow.this);
+ }
+ });
+
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/windows/Subwindow.java b/src/com/vaadin/demo/sampler/features/windows/Subwindow.java
new file mode 100644
index 0000000000..aa7d1f48c4
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/Subwindow.java
@@ -0,0 +1,38 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class Subwindow extends Feature {
+
+ @Override
+ public String getName() {
+ return "Subwindow";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A <i>Subwindow</i> is a popup-window within the browser window."
+ + " There can be multiple subwindows in one (native) browser"
+ + " window.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { NativeWindow.class, FeatureSet.Windows.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSized.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSized.java
new file mode 100644
index 0000000000..1b8b5e32cd
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSized.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class SubwindowAutoSized extends Feature {
+
+ @Override
+ public String getName() {
+ return "Window, automatic size";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The window will be automatically sized to fit the contents,"
+ + " if the size of the window (and it's layout) is undefined.<br/>"
+ + " Note that by default Window contains a VerticalLayout that"
+ + " is 100% wide.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { SubwindowSized.class, FeatureSet.Windows.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSizedExample.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSizedExample.java
new file mode 100644
index 0000000000..e2f0a60e3d
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowAutoSizedExample.java
@@ -0,0 +1,65 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SubwindowAutoSizedExample extends VerticalLayout {
+
+ Window subwindow;
+
+ public SubwindowAutoSizedExample() {
+
+ // Create the window
+ subwindow = new Window("Automatically sized subwindow");
+
+ // Configure the windws layout; by default a VerticalLayout
+ VerticalLayout layout = (VerticalLayout) subwindow.getLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+ // make it undefined for auto-sizing window
+ layout.setSizeUndefined();
+
+ // Add some content;
+ for (int i = 0; i < 7; i++) {
+ TextField tf = new TextField();
+ tf.setWidth("400px");
+ subwindow.addComponent(tf);
+ }
+
+ Button close = new Button("Close", new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ // close the window by removing it from the main window
+ getApplication().getMainWindow().removeWindow(subwindow);
+ }
+ });
+ // The components added to the window are actually added to the window's
+ // layout; you can use either. Alignments are set using the layout
+ layout.addComponent(close);
+ layout.setComponentAlignment(close, "right bottom");
+
+ // Add a button for opening the subwindow
+ Button open = new Button("Open sized window",
+ new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() != null) {
+ // window is already showing
+ getWindow().showNotification(
+ "Window is already open");
+ } else {
+ // Open the subwindow by adding it to the main
+ // window
+ getApplication().getMainWindow().addWindow(
+ subwindow);
+ }
+ }
+ });
+ addComponent(open);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowClose.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowClose.java
new file mode 100644
index 0000000000..6c572bd20c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowClose.java
@@ -0,0 +1,36 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class SubwindowClose extends Feature {
+
+ @Override
+ public String getName() {
+ return "Window closing";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Using a <i>CloseListener</i> one can detect when a window is closed.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Windows.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowCloseExample.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowCloseExample.java
new file mode 100644
index 0000000000..2b0f0073c0
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowCloseExample.java
@@ -0,0 +1,52 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Window.CloseEvent;
+
+public class SubwindowCloseExample extends VerticalLayout {
+
+ Window subwindow;
+
+ public SubwindowCloseExample() {
+
+ // Create the window
+ subwindow = new Window("A subwindow w/ close-listener");
+ subwindow.addListener(new Window.CloseListener() {
+ // inline close-listener
+ public void windowClose(CloseEvent e) {
+ getApplication().getMainWindow().showNotification(
+ "Window closed");
+ }
+ });
+
+ // Configure the windws layout; by default a VerticalLayout
+ VerticalLayout layout = (VerticalLayout) subwindow.getLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+
+ // Add some content; a label and a close-button
+ Label message = new Label("This is a subwindow with a close-listener.");
+ subwindow.addComponent(message);
+
+ // Add a button for opening the subwindow
+ Button open = new Button("Open window", new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() != null) {
+ // window is already showing
+ getWindow().showNotification("Window is already open");
+ } else {
+ // Open the subwindow by adding it to the main window
+ getApplication().getMainWindow().addWindow(subwindow);
+ }
+ }
+ });
+ addComponent(open);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowExample.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowExample.java
new file mode 100644
index 0000000000..cb48201acc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowExample.java
@@ -0,0 +1,56 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SubwindowExample extends VerticalLayout {
+
+ Window subwindow;
+
+ public SubwindowExample() {
+
+ // Create the window
+ subwindow = new Window("A subwindow");
+
+ // Configure the windws layout; by default a VerticalLayout
+ VerticalLayout layout = (VerticalLayout) subwindow.getLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+
+ // Add some content; a label and a close-button
+ Label message = new Label("This is a subwindow");
+ subwindow.addComponent(message);
+
+ Button close = new Button("Close", new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ // close the window by removing it from the main window
+ getApplication().getMainWindow().removeWindow(subwindow);
+ }
+ });
+ // The components added to the window are actually added to the window's
+ // layout; you can use either. Alignments are set using the layout
+ layout.addComponent(close);
+ layout.setComponentAlignment(close, "right");
+
+ // Add a button for opening the subwindow
+ Button open = new Button("Open subwindow", new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() != null) {
+ // window is already showing
+ getWindow().showNotification("Window is already open");
+ } else {
+ // Open the subwindow by adding it to the main window
+ getApplication().getMainWindow().addWindow(subwindow);
+ }
+ }
+ });
+ addComponent(open);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowModal.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowModal.java
new file mode 100644
index 0000000000..28c93c1ae0
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowModal.java
@@ -0,0 +1,47 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class SubwindowModal extends Feature {
+
+ @Override
+ public String getName() {
+ return "Modal window";
+ }
+
+ @Override
+ public String getDescription() {
+ return "A <i>modal window</i> blocks access to the rest of the application"
+ + " until the window is closed (or made non-modal).<br/>"
+ + " Use modal windows when the user must finish the task in the"
+ + " window before continuing.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] {
+ //
+ Subwindow.class, //
+ FeatureSet.Windows.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return new NamedExternalResource[] {
+ //
+ new NamedExternalResource("Wikipedia: Modal window",
+ "http://en.wikipedia.org/wiki/Modal_window"), //
+
+ };
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowModalExample.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowModalExample.java
new file mode 100644
index 0000000000..15ee9f040a
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowModalExample.java
@@ -0,0 +1,62 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SubwindowModalExample extends VerticalLayout {
+
+ Window subwindow;
+
+ public SubwindowModalExample() {
+
+ // Create the window...
+ subwindow = new Window("A modal subwindow");
+ // ...and make it modal
+ subwindow.setModal(true);
+
+ // Configure the windws layout; by default a VerticalLayout
+ VerticalLayout layout = (VerticalLayout) subwindow.getLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+
+ // Add some content; a label and a close-button
+ Label message = new Label("This is a modal subwindow.");
+ subwindow.addComponent(message);
+
+ Button close = new Button("Close", new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ // close the window by removing it from the main window
+ getApplication().getMainWindow().removeWindow(subwindow);
+ }
+ });
+ // The components added to the window are actually added to the window's
+ // layout; you can use either. Alignments are set using the layout
+ layout.addComponent(close);
+ layout.setComponentAlignment(close, "right");
+
+ // Add a button for opening the subwindow
+ Button open = new Button("Open modal window",
+ new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() != null) {
+ // window is already showing
+ getWindow().showNotification(
+ "Window is already open");
+ } else {
+ // Open the subwindow by adding it to the main
+ // window
+ getApplication().getMainWindow().addWindow(
+ subwindow);
+ }
+ }
+ });
+ addComponent(open);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowPositioned.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowPositioned.java
new file mode 100644
index 0000000000..3da56d87bc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowPositioned.java
@@ -0,0 +1,36 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class SubwindowPositioned extends Feature {
+
+ @Override
+ public String getName() {
+ return "Window position";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The position of a window can be specified, or it can be centered.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { FeatureSet.Windows.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowPositionedExample.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowPositionedExample.java
new file mode 100644
index 0000000000..f50bf0a21b
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowPositionedExample.java
@@ -0,0 +1,99 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SubwindowPositionedExample extends VerticalLayout {
+
+ Window subwindow;
+
+ public SubwindowPositionedExample() {
+ setSpacing(true);
+
+ // Create the window
+ subwindow = new Window("A positioned subwindow");
+ // let's give it a size (optional)
+ subwindow.setWidth("300px");
+ subwindow.setHeight("200px");
+
+ // Configure the windws layout; by default a VerticalLayout
+ VerticalLayout layout = (VerticalLayout) subwindow.getLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+ // make it fill the whole window
+ layout.setSizeFull();
+
+ // Add some content; a label and a close-button
+ Label message = new Label("This is a positioned window");
+ subwindow.addComponent(message);
+
+ Button close = new Button("Close", new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ // close the window by removing it from the main window
+ getApplication().getMainWindow().removeWindow(subwindow);
+ }
+ });
+ // The components added to the window are actually added to the window's
+ // layout; you can use either. Alignments are set using the layout
+ layout.addComponent(close);
+ layout.setComponentAlignment(close, "right bottom");
+
+ // Add buttons for opening the subwindow
+ Button fifty = new Button("Open window at position 50x50",
+ new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() == null) {
+ // Open the subwindow by adding it to the main
+ // window
+ getApplication().getMainWindow().addWindow(
+ subwindow);
+ }
+
+ // Set window position
+ subwindow.setPositionX(50);
+ subwindow.setPositionY(50);
+ }
+ });
+ addComponent(fifty);
+ Button onefifty = new Button("Open window at position 150x200",
+ new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() == null) {
+ // Open the subwindow by adding it to the main
+ // window
+ getApplication().getMainWindow().addWindow(
+ subwindow);
+ }
+
+ // Set window position
+ subwindow.setPositionX(150);
+ subwindow.setPositionY(200);
+ }
+ });
+ addComponent(onefifty);
+ Button center = new Button("Open centered window",
+ new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() == null) {
+ // Open the subwindow by adding it to the main
+ // window
+ getApplication().getMainWindow().addWindow(
+ subwindow);
+ }
+
+ // Center the window
+ subwindow.center();
+ }
+ });
+ addComponent(center);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowSized.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowSized.java
new file mode 100644
index 0000000000..ad03155d30
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowSized.java
@@ -0,0 +1,37 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.demo.sampler.APIResource;
+import com.vaadin.demo.sampler.Feature;
+import com.vaadin.demo.sampler.FeatureSet;
+import com.vaadin.demo.sampler.NamedExternalResource;
+import com.vaadin.ui.Window;
+
+public class SubwindowSized extends Feature {
+
+ @Override
+ public String getName() {
+ return "Window, explicit size";
+ }
+
+ @Override
+ public String getDescription() {
+ return "The size of a window can be specified - here the width is set"
+ + " in pixels, and the height in percent.";
+ }
+
+ @Override
+ public APIResource[] getRelatedAPI() {
+ return new APIResource[] { new APIResource(Window.class) };
+ }
+
+ @Override
+ public Class[] getRelatedFeatures() {
+ return new Class[] { SubwindowAutoSized.class, FeatureSet.Windows.class };
+ }
+
+ @Override
+ public NamedExternalResource[] getRelatedResources() {
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/features/windows/SubwindowSizedExample.java b/src/com/vaadin/demo/sampler/features/windows/SubwindowSizedExample.java
new file mode 100644
index 0000000000..93703773e2
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/features/windows/SubwindowSizedExample.java
@@ -0,0 +1,64 @@
+package com.vaadin.demo.sampler.features.windows;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SubwindowSizedExample extends VerticalLayout {
+
+ Window subwindow;
+
+ public SubwindowSizedExample() {
+
+ // Create the window
+ subwindow = new Window("A sized subwindow");
+ subwindow.setWidth("500px");
+ subwindow.setHeight("80%");
+
+ // Configure the windws layout; by default a VerticalLayout
+ VerticalLayout layout = (VerticalLayout) subwindow.getLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+ // make it fill the whole window
+ layout.setSizeFull();
+
+ // Add some content; a label and a close-button
+ Label message = new Label("This is a sized window");
+ subwindow.addComponent(message);
+
+ Button close = new Button("Close", new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ // close the window by removing it from the main window
+ getApplication().getMainWindow().removeWindow(subwindow);
+ }
+ });
+ // The components added to the window are actually added to the window's
+ // layout; you can use either. Alignments are set using the layout
+ layout.addComponent(close);
+ layout.setComponentAlignment(close, "right bottom");
+
+ // Add a button for opening the subwindow
+ Button open = new Button("Open sized window",
+ new Button.ClickListener() {
+ // inline click-listener
+ public void buttonClick(ClickEvent event) {
+ if (subwindow.getParent() != null) {
+ // window is already showing
+ getWindow().showNotification(
+ "Window is already open");
+ } else {
+ // Open the subwindow by adding it to the main
+ // window
+ getApplication().getMainWindow().addWindow(
+ subwindow);
+ }
+ }
+ });
+ addComponent(open);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/folder.gif b/src/com/vaadin/demo/sampler/folder.gif
new file mode 100644
index 0000000000..8dc04c4956
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/folder.gif
Binary files differ
diff --git a/src/com/vaadin/demo/sampler/gwt/SamplerWidgetSet.gwt.xml b/src/com/vaadin/demo/sampler/gwt/SamplerWidgetSet.gwt.xml
new file mode 100644
index 0000000000..dc6d1b206c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/SamplerWidgetSet.gwt.xml
@@ -0,0 +1,15 @@
+<module>
+ <!-- Inherit the DefaultWidgetSet -->
+ <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" />
+
+ <!-- Tracker -->
+ <script src="http://www.google-analytics.com/ga.js" />
+
+ <!-- Prettify -->
+ <stylesheet src="prettify/prettify.css"/>
+ <script src="prettify/prettify.js" />
+
+ <!-- Entry point -->
+ <entry-point class="com.vaadin.demo.sampler.gwt.client.SamplerWidgetSet"/>
+
+</module>
diff --git a/src/com/vaadin/demo/sampler/gwt/client/SamplerWidgetSet.java b/src/com/vaadin/demo/sampler/gwt/client/SamplerWidgetSet.java
new file mode 100644
index 0000000000..2738b21990
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/client/SamplerWidgetSet.java
@@ -0,0 +1,40 @@
+package com.vaadin.demo.sampler.gwt.client;
+
+import com.vaadin.demo.sampler.gwt.client.ui.IActiveLink;
+import com.vaadin.demo.sampler.gwt.client.ui.ICodeLabel;
+import com.vaadin.demo.sampler.gwt.client.ui.IGoogleAnalytics;
+import com.vaadin.terminal.gwt.client.DefaultWidgetSet;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class SamplerWidgetSet extends DefaultWidgetSet {
+
+ @Override
+ public Paintable createWidget(UIDL uidl) {
+ final Class classType = resolveWidgetType(uidl);
+ if (IGoogleAnalytics.class == classType) {
+ return new IGoogleAnalytics();
+ } else if (ICodeLabel.class == classType) {
+ return new ICodeLabel();
+ } else if (IActiveLink.class == classType) {
+ return new IActiveLink();
+ } else {
+ return super.createWidget(uidl);
+ }
+ }
+
+ @Override
+ protected Class resolveWidgetType(UIDL uidl) {
+ final String tag = uidl.getTag();
+ if ("googleanalytics".equals(tag)) {
+ return IGoogleAnalytics.class;
+ } else if ("codelabel".equals(tag)) {
+ return ICodeLabel.class;
+ } else if ("activelink".equals(tag)) {
+ return IActiveLink.class;
+ } else {
+ return super.resolveWidgetType(uidl);
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/IActiveLink.java b/src/com/vaadin/demo/sampler/gwt/client/ui/IActiveLink.java
new file mode 100644
index 0000000000..d539ef5611
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/client/ui/IActiveLink.java
@@ -0,0 +1,89 @@
+package com.vaadin.demo.sampler.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.MouseListener;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.ILink;
+
+public class IActiveLink extends ILink {
+
+ String id;
+ ApplicationConnection client;
+ boolean listening = false;
+
+ public IActiveLink() {
+ addMouseListener(new MouseListener() {
+ public void onMouseDown(Widget sender, int x, int y) {
+ }
+
+ public void onMouseEnter(Widget sender) {
+ }
+
+ public void onMouseLeave(Widget sender) {
+ }
+
+ public void onMouseMove(Widget sender, int x, int y) {
+ }
+
+ public void onMouseUp(Widget sender, int x, int y) {
+ Event e = DOM.eventGetCurrentEvent();
+ if (e.getButton() == Event.BUTTON_MIDDLE) {
+ sendVariables();
+ }
+ }
+ });
+ }
+
+ /**
+ * Sends variables, returns true if default handler should be called (i.e if
+ * server is listening and the link was claimed to be opened by the client)
+ *
+ * @return
+ */
+ private boolean sendVariables() {
+ Event e = DOM.eventGetCurrentEvent();
+ boolean opened = (e.getCtrlKey() || e.getAltKey() || e.getShiftKey()
+ || e.getMetaKey() || e.getButton() == Event.BUTTON_MIDDLE);
+
+ // Works as ILink if no-one is listening
+ if (listening) {
+ if (opened) {
+ // ILink will open, notify server
+ client.updateVariable(id, "opened", true, false);
+ } else {
+ e.preventDefault();
+ }
+ client.updateVariable(id, "activated", true, true);
+ }
+ return !listening || opened;
+ }
+
+ @Override
+ public void onClick(Widget sender) {
+
+ if (sendVariables()) {
+ // run default if not listening, or we claimed link was opened
+ super.onClick(sender);
+ }
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Ensure correct implementation,
+ // but don't let container manage caption etc.
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+
+ // Save details
+ this.client = client;
+ id = uidl.getId();
+ listening = uidl.hasVariable("activated");
+
+ super.updateFromUIDL(uidl, client);
+ }
+
+}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/ICodeLabel.java b/src/com/vaadin/demo/sampler/gwt/client/ui/ICodeLabel.java
new file mode 100644
index 0000000000..a97d74e067
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/client/ui/ICodeLabel.java
@@ -0,0 +1,29 @@
+package com.vaadin.demo.sampler.gwt.client.ui;
+
+import com.google.gwt.dom.client.Element;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.ILabel;
+
+public class ICodeLabel extends ILabel {
+
+ public ICodeLabel() {
+ super();
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ super.updateFromUIDL(uidl, client);
+ Element pre = getElement().getFirstChildElement();
+ if (null != pre) {
+ pre.setClassName("prettyprint");
+ prettyPrint();
+ }
+ }
+
+ private native void prettyPrint()
+ /*-{
+ $wnd.prettyPrint();
+ }-*/;
+
+}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/IGoogleAnalytics.java b/src/com/vaadin/demo/sampler/gwt/client/ui/IGoogleAnalytics.java
new file mode 100644
index 0000000000..13e15fb32c
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/client/ui/IGoogleAnalytics.java
@@ -0,0 +1,70 @@
+package com.vaadin.demo.sampler.gwt.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class IGoogleAnalytics extends Widget implements Paintable {
+
+ public IGoogleAnalytics() {
+ setElement(Document.get().createDivElement());
+ if (BrowserInfo.get().isIE6()) {
+ getElement().getStyle().setProperty("overflow", "hidden");
+ getElement().getStyle().setProperty("height", "0");
+ getElement().getStyle().setProperty("width", "0");
+ }
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (isLocalHostUrl()) {
+ // Do not track localhost page views
+ return;
+ }
+ String trackerId = uidl.getStringAttribute("trackerid");
+ String pageId = uidl.getStringAttribute("pageid");
+ String domainName = uidl.getStringAttribute("domain");
+
+ String res = trackPageview(trackerId, pageId, domainName);
+ if (null != res) {
+ ApplicationConnection.getConsole().log(
+ "WebAnalytics.trackPageview(" + trackerId + "," + pageId
+ + "," + domainName + ") FAILED: " + res);
+ } else {
+ ApplicationConnection.getConsole().log(
+ "WebAnalytics.trackPageview(" + trackerId + "," + pageId
+ + "," + domainName + ") SUCCESS.");
+ }
+ }
+
+ private native boolean isLocalHostUrl()
+ /*-{
+ var location = $wnd.location;
+ var re = /^http:\/\/(localhost|127.0.0.1)/;
+ return re.test(location);
+ }-*/;
+
+ private native String trackPageview(String trackerId, String pageId,
+ String domainName)
+ /*-{
+ if (!$wnd._gat) {
+ return "Tracker not found (running offline?)";
+ }
+ try {
+ var pageTracker = $wnd._gat._getTracker(trackerId);
+ if (domainName) {
+ pageTracker._setDomainName(domainName);
+ }
+ if (pageId) {
+ pageTracker._trackPageview(pageId);
+ } else {
+ pageTracker._trackPageview();
+ }
+ return null;
+ } catch(err) {
+ return ""+err;
+ }
+ }-*/;
+}
diff --git a/src/com/vaadin/demo/sampler/gwt/public/prettify/README.txt b/src/com/vaadin/demo/sampler/gwt/public/prettify/README.txt
new file mode 100644
index 0000000000..e39bfb78fc
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/public/prettify/README.txt
@@ -0,0 +1,3 @@
+google-code-prettify
+http://code.google.com/p/google-code-prettify/
+Apache License 2.0
diff --git a/src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.css b/src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.css
new file mode 100644
index 0000000000..647fc61472
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.css
@@ -0,0 +1 @@
+.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun{color:#660}.pln{color:#000}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec{color:#606}@media print{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun{color:#440}.pln{color:#000}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}} \ No newline at end of file
diff --git a/src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.js b/src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.js
new file mode 100644
index 0000000000..f8f4f7f461
--- /dev/null
+++ b/src/com/vaadin/demo/sampler/gwt/public/prettify/prettify.js
@@ -0,0 +1,25 @@
+function _pr_isIE6(){var F=navigator&&navigator.userAgent&&/\bMSIE 6\./.test(navigator.userAgent);_pr_isIE6=function(){return F};return F}var aa="break continue do else for if return while ",ba="auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile ",ca="catch class delete false import new operator private protected public this throw true try ",da="alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where ",
+ea="boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient ",fa="as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var ",ga="debugger eval export function get null set undefined var with Infinity NaN ",ha="caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END ",
+ia="and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None ",ja="alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END ",ka="case done elif esac eval fi function in local set then until ",la="a",ma="z",na="A",oa="Z",pa="!",qa="!=",ra="!==",s="#",sa="%",Ha="%=",v="&",Ia="&&",Ja="&&=",Ka="&=",La=
+"(",Ma="*",Na="*=",Oa="+=",Pa=",",Qa="-=",Ra="->",w="/",Sa="/=",Ta=":",Ua="::",y=";",z="<",Va="<<",Wa="<<=",Xa="<=",Ya="=",Za="==",$a="===",A=">",ab=">=",bb=">>",cb=">>=",db=">>>",eb=">>>=",fb="?",C="@",gb="[",hb="^",ib="^=",jb="^^",kb="^^=",lb="{",mb="|",nb="|=",ob="||",pb="||=",qb="~",rb="break",sb="case",tb="continue",ub="delete",vb="do",wb="else",xb="finally",yb="instanceof",zb="return",Ab="throw",Bb="try",Cb="typeof",Db="(?:(?:(?:^|[^0-9.])\\.{1,3})|(?:(?:^|[^\\+])\\+)|(?:(?:^|[^\\-])-)",Eb=
+"|\\b",Fb="\\$1",Gb="|^)\\s*$",Hb="&amp;",Ib="&lt;",Jb="&gt;",Kb="&quot;",Lb="&#",Mb="x",Nb="'",G='"',Ob=" ",Pb="XMP",Qb="</",Rb='="',H="PRE",Sb='<!DOCTYPE foo PUBLIC "foo bar">\n<foo />',I="",Tb="\t",Ub="\n",Vb="nocode",Wb=' $1="$2$3$4"',J="pln",O="com",Xb="dec",P="src",Q="tag",R="atv",S="pun",Yb="<>/=",X="atn",Zb=" \t\r\n",Y="str",$b="'\"",ac="'\"`",bc="\"'",cc=" \r\n",Z="lit",dc="123456789",ec=".",fc="kwd",gc="typ",$="</span>",hc='<span class="',ic='">',jc="$1&nbsp;",kc="<br />",lc="console",mc=
+"cannot override language handler %s",nc="default-code",oc="default-markup",pc="html",qc="htm",rc="xhtml",sc="xml",tc="xsl",uc="c",vc="cc",wc="cpp",xc="cs",yc="cxx",zc="cyc",Ac="java",Bc="bsh",Cc="csh",Dc="sh",Ec="cv",Fc="py",Gc="perl",Hc="pl",Ic="pm",Jc="rb",Kc="js",Lc="pre",Mc="code",Nc="xmp",Oc="prettyprint",Pc="class",Qc="br",Rc="\r\n";(function(){function F(b){b=b.split(/ /g);var a={};for(var c=b.length;--c>=0;){var d=b[c];if(d)a[d]=null}return a}var K=aa,Sc=K+ba,T=Sc+ca,ta=T+da,ua=T+ea,Tc=ua+
+fa,va=T+ga,wa=ha,xa=K+ia,ya=K+ja,za=K+ka,Uc=ta+Tc+va+wa+xa+ya+za;function Vc(b){return b>=la&&b<=ma||b>=na&&b<=oa}function D(b,a,c,d){b.unshift(c,d||0);try{a.splice.apply(a,b)}finally{b.splice(0,2)}}var Wc=(function(){var b=[pa,qa,ra,s,sa,Ha,v,Ia,Ja,Ka,La,Ma,Na,Oa,Pa,Qa,Ra,w,Sa,Ta,Ua,y,z,Va,Wa,Xa,Ya,Za,$a,A,ab,bb,cb,db,eb,fb,C,gb,hb,ib,jb,kb,lb,mb,nb,ob,pb,qb,rb,sb,tb,ub,vb,wb,xb,yb,zb,Ab,Bb,Cb],a=Db;for(var c=0;c<b.length;++c){var d=b[c];a+=Vc(d.charAt(0))?Eb+d:mb+d.replace(/([^=<>:&])/g,Fb)}a+=
+Gb;return new RegExp(a)})(),Aa=/&/g,Ba=/</g,Ca=/>/g,Xc=/\"/g;function Yc(b){return b.replace(Aa,Hb).replace(Ba,Ib).replace(Ca,Jb).replace(Xc,Kb)}function U(b){return b.replace(Aa,Hb).replace(Ba,Ib).replace(Ca,Jb)}var Zc=/&lt;/g,$c=/&gt;/g,ad=/&apos;/g,bd=/&quot;/g,cd=/&amp;/g,dd=/&nbsp;/g;function ed(b){var a=b.indexOf(v);if(a<0)return b;for(--a;(a=b.indexOf(Lb,a+1))>=0;){var c=b.indexOf(y,a);if(c>=0){var d=b.substring(a+3,c),g=10;if(d&&d.charAt(0)===Mb){d=d.substring(1);g=16}var e=parseInt(d,g);
+if(!isNaN(e))b=b.substring(0,a)+String.fromCharCode(e)+b.substring(c+1)}}return b.replace(Zc,z).replace($c,A).replace(ad,Nb).replace(bd,G).replace(cd,v).replace(dd,Ob)}function Da(b){return Pb===b.tagName}function L(b,a){switch(b.nodeType){case 1:var c=b.tagName.toLowerCase();a.push(z,c);for(var d=0;d<b.attributes.length;++d){var g=b.attributes[d];if(!g.specified)continue;a.push(Ob);L(g,a)}a.push(A);for(var e=b.firstChild;e;e=e.nextSibling)L(e,a);if(b.firstChild||!/^(?:br|link|img)$/.test(c))a.push(Qb,
+c,A);break;case 2:a.push(b.name.toLowerCase(),Rb,Yc(b.value),G);break;case 3:case 4:a.push(U(b.nodeValue));break}}var V=null;function fd(b){if(null===V){var a=document.createElement(H);a.appendChild(document.createTextNode(Sb));V=!/</.test(a.innerHTML)}if(V){var c=b.innerHTML;if(Da(b))c=U(c);return c}var d=[];for(var g=b.firstChild;g;g=g.nextSibling)L(g,d);return d.join(I)}function gd(b){var a=0;return function(c){var d=null,g=0;for(var e=0,h=c.length;e<h;++e){var f=c.charAt(e);switch(f){case Tb:if(!d)d=
+[];d.push(c.substring(g,e));var i=b-a%b;a+=i;for(;i>=0;i-=" ".length)d.push(" ".substring(0,i));g=e+1;break;case Ub:a=0;break;default:++a}}if(!d)return c;d.push(c.substring(g));return d.join(I)}}var hd=/(?:[^<]+|<!--[\s\S]*?--\>|<!\[CDATA\[([\s\S]*?)\]\]>|<\/?[a-zA-Z][^>]*>|<)/g,id=/^<!--/,jd=/^<\[CDATA\[/,kd=/^<br\b/i,Ea=/^<(\/?)([a-zA-Z]+)/;function ld(b){var a=b.match(hd),c=[],d=0,g=[];if(a)for(var e=0,h=a.length;e<h;++e){var f=a[e];if(f.length>1&&f.charAt(0)===z){if(id.test(f))continue;
+if(jd.test(f)){c.push(f.substring(9,f.length-3));d+=f.length-12}else if(kd.test(f)){c.push(Ub);++d}else if(f.indexOf(Vb)>=0&&!!f.replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,Wb).match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/)){var i=f.match(Ea)[2],j=1;end_tag_loop:for(var m=e+1;m<h;++m){var o=a[m].match(Ea);if(o&&o[2]===i)if(o[1]===w){if(--j===0)break end_tag_loop}else++j}if(m<h){g.push(d,a.slice(e,m+1).join(I));e=m}else g.push(d,f)}else g.push(d,f)}else{var k=ed(f);c.push(k);d+=k.length}}return{source:c.join(I),
+tags:g}}function E(b,a){var c={};(function(){var e=b.concat(a);for(var h=e.length;--h>=0;){var f=e[h],i=f[3];if(i)for(var j=i.length;--j>=0;)c[i.charAt(j)]=f}})();var d=a.length,g=/\S/;return function(e,h){h=h||0;var f=[h,J],i=I,j=0,m=e;while(m.length){var o,k=null,p,l=c[m.charAt(0)];if(l){p=m.match(l[1]);k=p[0];o=l[0]}else{for(var n=0;n<d;++n){l=a[n];var q=l[2];if(q&&!q.test(i))continue;p=m.match(l[1]);if(p){k=p[0];o=l[0];break}}if(!k){o=J;k=m.substring(0,1)}}f.push(h+j,o);j+=k.length;m=m.substring(k.length);
+if(o!==O&&g.test(k))i=k}return f}}var md=E([],[[J,/^[^<]+/,null],[Xb,/^<!\w[^>]*(?:>|$)/,null],[O,/^<!--[\s\S]*?(?:--\>|$)/,null],[P,/^<\?[\s\S]*?(?:\?>|$)/,null],[P,/^<%[\s\S]*?(?:%>|$)/,null],[P,/^<(script|style|xmp)\b[^>]*>[\s\S]*?<\/\1\b[^>]*>/i,null],[Q,/^<\/?\w[^<>]*>/,null]]);function nd(b){var a=md(b);for(var c=0;c<a.length;c+=2)if(a[c+1]===P){var d,g;d=a[c];g=c+2<a.length?a[c+2]:b.length;var e=b.substring(d,g),h=e.match(/^(<[^>]*>)([\s\S]*)(<\/[^>]*>)$/);if(h)a.splice(c,2,d,Q,d+h[1].length,
+P,d+h[1].length+(h[2]||I).length,Q)}return a}var od=E([[R,/^\'[^\']*(?:\'|$)/,null,Nb],[R,/^\"[^\"]*(?:\"|$)/,null,G],[S,/^[<>\/=]+/,null,Yb]],[[Q,/^[\w:\-]+/,/^</],[R,/^[\w\-]+/,/^=/],[X,/^[\w:\-]+/,null],[J,/^\s+/,null,Zb]]);function pd(b,a){for(var c=0;c<a.length;c+=2){var d=a[c+1];if(d===Q){var g,e;g=a[c];e=c+2<a.length?a[c+2]:b.length;var h=b.substring(g,e),f=od(h,g);D(f,a,c,2);c+=f.length-2}}return a}function u(b){var a=[],c=[];if(b.tripleQuotedStrings)a.push([Y,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
+null,$b]);else if(b.multiLineStrings)a.push([Y,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,ac]);else a.push([Y,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,bc]);c.push([J,/^(?:[^\'\"\`\/\#]+)/,null,cc]);if(b.hashComments)a.push([O,/^#[^\r\n]*/,null,s]);if(b.cStyleComments){c.push([O,/^\/\/[^\r\n]*/,null]);c.push([O,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(b.regexLiterals)c.push([Y,/^\/(?=[^\/*])(?:[^\/\x5B\x5C]|\x5C[\s\S]|\x5B(?:[^\x5C\x5D]|\x5C[\s\S])*(?:\x5D|$))+(?:\/|$)/,
+Wc]);var d=F(b.keywords);b=null;var g=E(a,c),e=E([],[[J,/^\s+/,null,cc],[J,/^[a-z_$@][a-z_$@0-9]*/i,null],[Z,/^0x[a-f0-9]+[a-z]/i,null],[Z,/^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i,null,dc],[S,/^[^\s\w\.$@]+/,null]]);function h(f,i){for(var j=0;j<i.length;j+=2){var m=i[j+1];if(m===J){var o,k,p,l;o=i[j];k=j+2<i.length?i[j+2]:f.length;p=f.substring(o,k);l=e(p,o);for(var n=0,q=l.length;n<q;n+=2){var r=l[n+1];if(r===J){var B=l[n],M=n+2<q?l[n+2]:p.length,x=f.substring(B,M);if(x===ec)l[n+
+1]=S;else if(x in d)l[n+1]=fc;else if(/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(x))l[n+1]=x.charAt(0)===C?Z:gc}}D(l,i,j,2);j+=l.length-2}}return i}return function(f){var i=g(f);i=h(f,i);return i}}var W=u({keywords:Uc,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function qd(b,a){for(var c=0;c<a.length;c+=2){var d=a[c+1];if(d===P){var g,e;g=a[c];e=c+2<a.length?a[c+2]:b.length;var h=W(b.substring(g,e));for(var f=0,i=h.length;f<i;f+=2)h[f]+=g;D(h,a,c,2);c+=h.length-2}}return a}
+function rd(b,a){var c=false;for(var d=0;d<a.length;d+=2){var g=a[d+1],e,h;if(g===X){e=a[d];h=d+2<a.length?a[d+2]:b.length;c=/^on|^style$/i.test(b.substring(e,h))}else if(g===R){if(c){e=a[d];h=d+2<a.length?a[d+2]:b.length;var f=b.substring(e,h),i=f.length,j=i>=2&&/^[\"\']/.test(f)&&f.charAt(0)===f.charAt(i-1),m,o,k;if(j){o=e+1;k=h-1;m=f}else{o=e+1;k=h-1;m=f.substring(1,f.length-1)}var p=W(m);for(var l=0,n=p.length;l<n;l+=2)p[l]+=o;if(j){p.push(k,R);D(p,a,d+2,0)}else D(p,a,d,2)}c=false}}return a}function sd(b){var a=
+nd(b);a=pd(b,a);a=qd(b,a);a=rd(b,a);return a}function td(b,a,c){var d=[],g=0,e=null,h=null,f=0,i=0,j=gd(8),m=/([\r\n ]) /g,o=/(^| ) /gm,k=/\r\n?|\n/g,p=/[ \r\n]$/,l=true;function n(r){if(r>g){if(e&&e!==h){d.push($);e=null}if(!e&&h){e=h;d.push(hc,e,ic)}var B=U(j(b.substring(g,r))).replace(l?o:m,jc);l=p.test(B);d.push(B.replace(k,kc));g=r}}while(true){var q;q=f<a.length?(i<c.length?a[f]<=c[i]:true):false;if(q){n(a[f]);if(e){d.push($);e=null}d.push(a[f+1]);f+=2}else if(i<c.length){n(c[i]);h=c[i+1];i+=
+2}else break}n(b.length);if(e)d.push($);return d.join(I)}var N={};function t(b,a){for(var c=a.length;--c>=0;){var d=a[c];if(!N.hasOwnProperty(d))N[d]=b;else if(lc in window)console.log(mc,d)}}t(W,[nc]);t(sd,[oc,pc,qc,rc,sc,tc]);t(u({keywords:ta,hashComments:true,cStyleComments:true}),[uc,vc,wc,xc,yc,zc]);t(u({keywords:ua,cStyleComments:true}),[Ac]);t(u({keywords:za,hashComments:true,multiLineStrings:true}),[Bc,Cc,Dc]);t(u({keywords:xa,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),
+[Ec,Fc]);t(u({keywords:wa,hashComments:true,multiLineStrings:true,regexLiterals:true}),[Gc,Hc,Ic]);t(u({keywords:ya,hashComments:true,multiLineStrings:true,regexLiterals:true}),[Jc]);t(u({keywords:va,cStyleComments:true,regexLiterals:true}),[Kc]);function Fa(b,a){try{var c=ld(b),d=c.source,g=c.tags;if(!N.hasOwnProperty(a))a=/^\s*</.test(d)?oc:nc;var e=N[a].call({},d);return td(d,g,e)}catch(h){if(lc in window){console.log(h);console.trace()}return b}}function ud(b){var a=_pr_isIE6(),c=[document.getElementsByTagName(Lc),
+document.getElementsByTagName(Mc),document.getElementsByTagName(Nc)],d=[];for(var g=0;g<c.length;++g)for(var e=0;e<c[g].length;++e)d.push(c[g][e]);c=null;var h=0;function f(){var i=(new Date).getTime()+250;for(;h<d.length&&(new Date).getTime()<i;h++){var j=d[h];if(j.className&&j.className.indexOf(Oc)>=0){var m=j.className.match(/\blang-(\w+)\b/);if(m)m=m[1];var o=false;for(var k=j.parentNode;k;k=k.parentNode)if((k.tagName===Lc||k.tagName===Mc||k.tagName===Nc)&&k.className&&k.className.indexOf(Oc)>=
+0){o=true;break}if(!o){var p=fd(j);p=p.replace(/(?:\r\n?|\n)$/,I);var l=Fa(p,m);if(!Da(j))j.innerHTML=l;else{var n=document.createElement(H);for(var q=0;q<j.attributes.length;++q){var r=j.attributes[q];if(r.specified){var B=r.name.toLowerCase();if(B===Pc)n.className=r.value;else n.setAttribute(r.name,r.value)}}n.innerHTML=l;j.parentNode.replaceChild(n,j);j=n}if(a&&j.tagName===H){var M=j.getElementsByTagName(Qc);for(var x=M.length;--x>=0;){var Ga=M[x];Ga.parentNode.replaceChild(document.createTextNode(Rc),
+Ga)}}}}}if(h<d.length)setTimeout(f,250);else if(b)b()}f()}window.PR_normalizedHtml=L;window.prettyPrintOne=Fa;window.prettyPrint=ud;window.PR={createSimpleLexer:E,registerLangHandler:t,sourceDecorator:u,PR_ATTRIB_NAME:X,PR_ATTRIB_VALUE:R,PR_COMMENT:O,PR_DECLARATION:Xb,PR_KEYWORD:fc,PR_LITERAL:Z,PR_NOCODE:Vb,PR_PLAIN:J,PR_PUNCTUATION:S,PR_SOURCE:P,PR_STRING:Y,PR_TAG:Q,PR_TYPE:gc}})();
diff --git a/src/com/vaadin/demo/tutorial/addressbook/AddressBookApplication.java b/src/com/vaadin/demo/tutorial/addressbook/AddressBookApplication.java
new file mode 100644
index 0000000000..ad61246c22
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/AddressBookApplication.java
@@ -0,0 +1,244 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.tutorial.addressbook;
+
+import com.vaadin.Application;
+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.demo.tutorial.addressbook.data.PersonContainer;
+import com.vaadin.demo.tutorial.addressbook.data.SearchFilter;
+import com.vaadin.demo.tutorial.addressbook.ui.HelpWindow;
+import com.vaadin.demo.tutorial.addressbook.ui.ListView;
+import com.vaadin.demo.tutorial.addressbook.ui.NavigationTree;
+import com.vaadin.demo.tutorial.addressbook.ui.PersonForm;
+import com.vaadin.demo.tutorial.addressbook.ui.PersonList;
+import com.vaadin.demo.tutorial.addressbook.ui.SearchView;
+import com.vaadin.demo.tutorial.addressbook.ui.SharingOptions;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.SplitPanel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Window.Notification;
+
+public class AddressBookApplication extends Application implements
+ ClickListener, ValueChangeListener, ItemClickListener {
+
+ private NavigationTree tree = new NavigationTree(this);
+
+ private Button newContact = new Button("Add contact");
+ private Button search = new Button("Search");
+ private Button share = new Button("Share");
+ private Button help = new Button("Help");
+ private SplitPanel horizontalSplit = new SplitPanel(
+ SplitPanel.ORIENTATION_HORIZONTAL);
+
+ // Lazyly created ui references
+ private ListView listView = null;
+ private SearchView searchView = null;
+ private PersonList personList = null;
+ private PersonForm personForm = null;
+ private HelpWindow helpWindow = null;
+ private SharingOptions sharingOptions = null;
+
+ private PersonContainer dataSource = PersonContainer.createWithTestData();
+
+ @Override
+ public void init() {
+ buildMainLayout();
+ setMainComponent(getListView());
+ }
+
+ private void buildMainLayout() {
+ setMainWindow(new Window("Address Book Demo application"));
+
+ setTheme("contacts");
+
+ VerticalLayout layout = new VerticalLayout();
+ layout.setSizeFull();
+
+ layout.addComponent(createToolbar());
+ layout.addComponent(horizontalSplit);
+ layout.setExpandRatio(horizontalSplit, 1);
+
+ horizontalSplit.setSplitPosition(200, SplitPanel.UNITS_PIXELS);
+ horizontalSplit.setFirstComponent(tree);
+
+ getMainWindow().setLayout(layout);
+ }
+
+ private HorizontalLayout createToolbar() {
+ HorizontalLayout lo = new HorizontalLayout();
+ lo.addComponent(newContact);
+ lo.addComponent(search);
+ lo.addComponent(share);
+ lo.addComponent(help);
+
+ search.addListener((ClickListener) this);
+ share.addListener((ClickListener) this);
+ help.addListener((ClickListener) this);
+ newContact.addListener((ClickListener) this);
+
+ search.setIcon(new ThemeResource("icons/32/folder-add.png"));
+ share.setIcon(new ThemeResource("icons/32/users.png"));
+ help.setIcon(new ThemeResource("icons/32/help.png"));
+ newContact.setIcon(new ThemeResource("icons/32/document-add.png"));
+
+ lo.setMargin(true);
+ lo.setSpacing(true);
+
+ lo.setStyleName("toolbar");
+
+ lo.setWidth("100%");
+
+ Embedded em = new Embedded("", new ThemeResource("images/logo.png"));
+ lo.addComponent(em);
+ lo.setComponentAlignment(em, Alignment.MIDDLE_RIGHT);
+ lo.setExpandRatio(em, 1);
+
+ return lo;
+ }
+
+ private void setMainComponent(Component c) {
+ horizontalSplit.setSecondComponent(c);
+ }
+
+ /*
+ * View getters exist so we can lazily generate the views, resulting in
+ * faster application startup time.
+ */
+ private ListView getListView() {
+ if (listView == null) {
+ personList = new PersonList(this);
+ personForm = new PersonForm(this);
+ listView = new ListView(personList, personForm);
+ }
+ return listView;
+ }
+
+ private SearchView getSearchView() {
+ if (searchView == null) {
+ searchView = new SearchView(this);
+ }
+ return searchView;
+ }
+
+ private HelpWindow getHelpWindow() {
+ if (helpWindow == null) {
+ helpWindow = new HelpWindow();
+ }
+ return helpWindow;
+ }
+
+ private SharingOptions getSharingOptions() {
+ if (sharingOptions == null) {
+ sharingOptions = new SharingOptions();
+ }
+ return sharingOptions;
+ }
+
+ public PersonContainer getDataSource() {
+ return dataSource;
+ }
+
+ public void buttonClick(ClickEvent event) {
+ final Button source = event.getButton();
+
+ if (source == search) {
+ showSearchView();
+ } else if (source == help) {
+ showHelpWindow();
+ } else if (source == share) {
+ showShareWindow();
+ } else if (source == newContact) {
+ addNewContanct();
+ }
+ }
+
+ private void showHelpWindow() {
+ getMainWindow().addWindow(getHelpWindow());
+ }
+
+ private void showShareWindow() {
+ getMainWindow().addWindow(getSharingOptions());
+ }
+
+ private void showListView() {
+ setMainComponent(getListView());
+ }
+
+ private void showSearchView() {
+ setMainComponent(getSearchView());
+ }
+
+ public void valueChange(ValueChangeEvent event) {
+ Property property = event.getProperty();
+ if (property == personList) {
+ Item item = personList.getItem(personList.getValue());
+ if (item != personForm.getItemDataSource()) {
+ personForm.setItemDataSource(item);
+ }
+ }
+ }
+
+ public void itemClick(ItemClickEvent event) {
+ if (event.getSource() == tree) {
+ Object itemId = event.getItemId();
+ if (itemId != null) {
+ if (itemId == NavigationTree.SHOW_ALL) {
+ // clear previous filters
+ getDataSource().removeAllContainerFilters();
+ showListView();
+ } else if (itemId == NavigationTree.SEARCH) {
+ showSearchView();
+ } else if (itemId instanceof SearchFilter) {
+ search((SearchFilter) itemId);
+ }
+ }
+ }
+ }
+
+ private void addNewContanct() {
+ showListView();
+ personForm.addContact();
+ }
+
+ public void search(SearchFilter searchFilter) {
+ // clear previous filters
+ getDataSource().removeAllContainerFilters();
+ // filter contacts with given filter
+ getDataSource().addContainerFilter(searchFilter.getPropertyId(),
+ searchFilter.getTerm(), true, false);
+ showListView();
+
+ getMainWindow().showNotification(
+ "Searched for " + searchFilter.getPropertyId() + "=*"
+ + searchFilter.getTerm() + "*, found "
+ + getDataSource().size() + " item(s).",
+ Notification.TYPE_TRAY_NOTIFICATION);
+ }
+
+ public void saveSearch(SearchFilter searchFilter) {
+ tree.addItem(searchFilter);
+ tree.setParent(searchFilter, NavigationTree.SEARCH);
+ // mark the saved search as a leaf (cannot have children)
+ tree.setChildrenAllowed(searchFilter, false);
+ // make sure "Search" is expanded
+ tree.expandItem(NavigationTree.SEARCH);
+ // select the saved search
+ tree.setValue(searchFilter);
+ }
+
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/data/Person.java b/src/com/vaadin/demo/tutorial/addressbook/data/Person.java
new file mode 100644
index 0000000000..772f3e143a
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/data/Person.java
@@ -0,0 +1,119 @@
+package com.vaadin.demo.tutorial.addressbook.data;
+
+import java.io.Serializable;
+
+public class Person implements Serializable {
+ private String firstName = "";
+ private String lastName = "";
+ private String email = "";
+ private String phoneNumber = "";
+ private String streetAddress = "";
+ private Integer postalCode = null;
+ private String city = "";
+
+ /**
+ * @return the firstName
+ */
+ public String getFirstName() {
+ return firstName;
+ }
+
+ /**
+ * @param firstName
+ * the firstName to set
+ */
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ /**
+ * @return the lastName
+ */
+ public String getLastName() {
+ return lastName;
+ }
+
+ /**
+ * @param lastName
+ * the lastName to set
+ */
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ /**
+ * @return the email
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * @param email
+ * the email to set
+ */
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ /**
+ * @return the phoneNumber
+ */
+ public String getPhoneNumber() {
+ return phoneNumber;
+ }
+
+ /**
+ * @param phoneNumber
+ * the phoneNumber to set
+ */
+ public void setPhoneNumber(String phoneNumber) {
+ this.phoneNumber = phoneNumber;
+ }
+
+ /**
+ * @return the streetAddress
+ */
+ public String getStreetAddress() {
+ return streetAddress;
+ }
+
+ /**
+ * @param streetAddress
+ * the streetAddress to set
+ */
+ public void setStreetAddress(String streetAddress) {
+ this.streetAddress = streetAddress;
+ }
+
+ /**
+ * @return the postalCode
+ */
+ public Integer getPostalCode() {
+ return postalCode;
+ }
+
+ /**
+ * @param postalCode
+ * the postalCode to set
+ */
+ public void setPostalCode(Integer postalCode) {
+ this.postalCode = postalCode;
+ }
+
+ /**
+ * @return the city
+ */
+ public String getCity() {
+ return city;
+ }
+
+ /**
+ * @param city
+ * the city to set
+ */
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/tutorial/addressbook/data/PersonContainer.java b/src/com/vaadin/demo/tutorial/addressbook/data/PersonContainer.java
new file mode 100644
index 0000000000..d0dfb262bf
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/data/PersonContainer.java
@@ -0,0 +1,93 @@
+package com.vaadin.demo.tutorial.addressbook.data;
+
+import java.io.Serializable;
+import java.util.Random;
+
+import com.vaadin.data.util.BeanItemContainer;
+
+public class PersonContainer extends BeanItemContainer<Person> implements
+ Serializable {
+
+ /**
+ * Natural property order for Person bean. Used in tables and forms.
+ */
+ public static final Object[] NATURAL_COL_ORDER = new Object[] {
+ "firstName", "lastName", "email", "phoneNumber", "streetAddress",
+ "postalCode", "city" };
+
+ /**
+ * "Human readable" captions for properties in same order as in
+ * NATURAL_COL_ORDER.
+ */
+ public static final String[] COL_HEADERS_ENGLISH = new String[] {
+ "First name", "Last name", "Email", "Phone number",
+ "Street Address", "Postal Code", "City" };
+
+ public PersonContainer() throws InstantiationException,
+ IllegalAccessException {
+ super(Person.class);
+ }
+
+ public static PersonContainer createWithTestData() {
+ final String[] fnames = { "Peter", "Alice", "Joshua", "Mike", "Olivia",
+ "Nina", "Alex", "Rita", "Dan", "Umberto", "Henrik", "Rene",
+ "Lisa", "Marge" };
+ final String[] lnames = { "Smith", "Gordon", "Simpson", "Brown",
+ "Clavel", "Simons", "Verne", "Scott", "Allison", "Gates",
+ "Rowling", "Barks", "Ross", "Schneider", "Tate" };
+ final String cities[] = { "Amsterdam", "Berlin", "Helsinki",
+ "Hong Kong", "London", "Luxemburg", "New York", "Oslo",
+ "Paris", "Rome", "Stockholm", "Tokyo", "Turku" };
+ final String streets[] = { "4215 Blandit Av.", "452-8121 Sem Ave",
+ "279-4475 Tellus Road", "4062 Libero. Av.", "7081 Pede. Ave",
+ "6800 Aliquet St.", "P.O. Box 298, 9401 Mauris St.",
+ "161-7279 Augue Ave", "P.O. Box 496, 1390 Sagittis. Rd.",
+ "448-8295 Mi Avenue", "6419 Non Av.",
+ "659-2538 Elementum Street", "2205 Quis St.",
+ "252-5213 Tincidunt St.", "P.O. Box 175, 4049 Adipiscing Rd.",
+ "3217 Nam Ave", "P.O. Box 859, 7661 Auctor St.",
+ "2873 Nonummy Av.", "7342 Mi, Avenue",
+ "539-3914 Dignissim. Rd.", "539-3675 Magna Avenue",
+ "Ap #357-5640 Pharetra Avenue", "416-2983 Posuere Rd.",
+ "141-1287 Adipiscing Avenue", "Ap #781-3145 Gravida St.",
+ "6897 Suscipit Rd.", "8336 Purus Avenue", "2603 Bibendum. Av.",
+ "2870 Vestibulum St.", "Ap #722 Aenean Avenue",
+ "446-968 Augue Ave", "1141 Ultricies Street",
+ "Ap #992-5769 Nunc Street", "6690 Porttitor Avenue",
+ "Ap #105-1700 Risus Street",
+ "P.O. Box 532, 3225 Lacus. Avenue", "736 Metus Street",
+ "414-1417 Fringilla Street", "Ap #183-928 Scelerisque Road",
+ "561-9262 Iaculis Avenue" };
+ PersonContainer c = null;
+ Random r = new Random(0);
+ try {
+ c = new PersonContainer();
+ for (int i = 0; i < 100; i++) {
+ Person p = new Person();
+ p.setFirstName(fnames[r.nextInt(fnames.length)]);
+ p.setLastName(lnames[r.nextInt(lnames.length)]);
+ p.setCity(cities[r.nextInt(cities.length)]);
+ p.setEmail(p.getFirstName().toLowerCase() + "."
+ + p.getLastName().toLowerCase() + "@itmill.com");
+ p.setPhoneNumber("+358 02 555 " + r.nextInt(10) + r.nextInt(10)
+ + r.nextInt(10) + r.nextInt(10));
+ int n = r.nextInt(100000);
+ if (n < 10000) {
+ n += 10000;
+ }
+ p.setPostalCode(n);
+ p.setStreetAddress(streets[r.nextInt(streets.length)]);
+ c.addItem(p);
+ }
+ } catch (InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return c;
+ }
+
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/data/SearchFilter.java b/src/com/vaadin/demo/tutorial/addressbook/data/SearchFilter.java
new file mode 100644
index 0000000000..fd7eb16ae9
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/data/SearchFilter.java
@@ -0,0 +1,43 @@
+package com.vaadin.demo.tutorial.addressbook.data;
+
+import java.io.Serializable;
+
+public class SearchFilter implements Serializable {
+
+ private final String term;
+ private final Object propertyId;
+ private String searchName;
+
+ public SearchFilter(Object propertyId, String searchTerm, String name) {
+ this.propertyId = propertyId;
+ term = searchTerm;
+ searchName = name;
+ }
+
+ /**
+ * @return the term
+ */
+ public String getTerm() {
+ return term;
+ }
+
+ /**
+ * @return the propertyId
+ */
+ public Object getPropertyId() {
+ return propertyId;
+ }
+
+ /**
+ * @return the name of the search
+ */
+ public String getSearchName() {
+ return searchName;
+ }
+
+ @Override
+ public String toString() {
+ return getSearchName();
+ }
+
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/ui/HelpWindow.java b/src/com/vaadin/demo/tutorial/addressbook/ui/HelpWindow.java
new file mode 100644
index 0000000000..17a553aadc
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/ui/HelpWindow.java
@@ -0,0 +1,17 @@
+package com.vaadin.demo.tutorial.addressbook.ui;
+
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+public class HelpWindow extends Window {
+ private static final String HELP_HTML_SNIPPET = "This is "
+ + "an application built during <strong><a href=\""
+ + "http://dev.itmill.com/\">Toolkit</a></strong> "
+ + "tutorial. Hopefully it don't need any real help.";
+
+ public HelpWindow() {
+ setCaption("Address Book help");
+ addComponent(new Label(HELP_HTML_SNIPPET, Label.CONTENT_XHTML));
+ }
+
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/ui/ListView.java b/src/com/vaadin/demo/tutorial/addressbook/ui/ListView.java
new file mode 100644
index 0000000000..4790e0ed3e
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/ui/ListView.java
@@ -0,0 +1,12 @@
+package com.vaadin.demo.tutorial.addressbook.ui;
+
+import com.vaadin.ui.SplitPanel;
+
+public class ListView extends SplitPanel {
+ public ListView(PersonList personList, PersonForm personForm) {
+ addStyleName("view");
+ setFirstComponent(personList);
+ setSecondComponent(personForm);
+ setSplitPosition(40);
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/tutorial/addressbook/ui/NavigationTree.java b/src/com/vaadin/demo/tutorial/addressbook/ui/NavigationTree.java
new file mode 100644
index 0000000000..f95c938beb
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/ui/NavigationTree.java
@@ -0,0 +1,28 @@
+package com.vaadin.demo.tutorial.addressbook.ui;
+
+import com.vaadin.demo.tutorial.addressbook.AddressBookApplication;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.ui.Tree;
+
+public class NavigationTree extends Tree {
+ public static final Object SHOW_ALL = "Show all";
+ public static final Object SEARCH = "Search";
+
+ public NavigationTree(AddressBookApplication app) {
+ addItem(SHOW_ALL);
+ addItem(SEARCH);
+
+ setChildrenAllowed(SHOW_ALL, false);
+
+ /*
+ * We want items to be selectable but do not want the user to be able to
+ * de-select an item.
+ */
+ setSelectable(true);
+ setNullSelectionAllowed(false);
+
+ // Make application handle item click events
+ addListener((ItemClickListener) app);
+
+ }
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/ui/PersonForm.java b/src/com/vaadin/demo/tutorial/addressbook/ui/PersonForm.java
new file mode 100644
index 0000000000..212c921ed0
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/ui/PersonForm.java
@@ -0,0 +1,176 @@
+package com.vaadin.demo.tutorial.addressbook.ui;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.demo.tutorial.addressbook.AddressBookApplication;
+import com.vaadin.demo.tutorial.addressbook.data.Person;
+import com.vaadin.demo.tutorial.addressbook.data.PersonContainer;
+import com.vaadin.demo.tutorial.addressbook.validators.EmailValidator;
+import com.vaadin.demo.tutorial.addressbook.validators.PostalCodeValidator;
+import com.vaadin.ui.BaseFieldFactory;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.Form;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+public class PersonForm extends Form implements ClickListener {
+
+ private Button save = new Button("Save", (ClickListener) this);
+ private Button cancel = new Button("Cancel", (ClickListener) this);
+ private Button edit = new Button("Edit", (ClickListener) this);
+ private final ComboBox cities = new ComboBox("City");
+
+ private AddressBookApplication app;
+ private boolean newContactMode = false;
+ private Person newPerson = null;
+
+ public PersonForm(AddressBookApplication app) {
+ this.app = app;
+
+ /*
+ * Enable buffering so that commit() must be called for the form before
+ * input is written to the data. (Form input is not written immediately
+ * through to the underlying object.)
+ */
+ setWriteThrough(false);
+
+ HorizontalLayout footer = new HorizontalLayout();
+ footer.setSpacing(true);
+ footer.addComponent(save);
+ footer.addComponent(cancel);
+ footer.addComponent(edit);
+ footer.setVisible(false);
+
+ setFooter(footer);
+
+ /* Allow the user to enter new cities */
+ cities.setNewItemsAllowed(true);
+ /* We do not want to use null values */
+ cities.setNullSelectionAllowed(false);
+ /* Add an empty city used for selecting no city */
+ cities.addItem("");
+
+ /* Populate cities select using the cities in the data container */
+ PersonContainer ds = app.getDataSource();
+ for (Iterator<Person> it = ds.getItemIds().iterator(); it.hasNext();) {
+ String city = (it.next()).getCity();
+ cities.addItem(city);
+ }
+
+ /*
+ * Field factory for overriding how the component for city selection is
+ * created
+ */
+ setFieldFactory(new BaseFieldFactory() {
+ @Override
+ public Field createField(Item item, Object propertyId,
+ Component uiContext) {
+ if (propertyId.equals("city")) {
+ cities.setWidth("200px");
+ return cities;
+ }
+
+ Field field = super.createField(item, propertyId, uiContext);
+ if (propertyId.equals("postalCode")) {
+ TextField tf = (TextField) field;
+ /*
+ * We do not want to display "null" to the user when the
+ * field is empty
+ */
+ tf.setNullRepresentation("");
+
+ /* Add a validator for postalCode and make it required */
+ tf.addValidator(new PostalCodeValidator());
+ tf.setRequired(true);
+ } else if (propertyId.equals("email")) {
+ /* Add a validator for email and make it required */
+ field.addValidator(new EmailValidator());
+ field.setRequired(true);
+
+ }
+
+ field.setWidth("200px");
+ return field;
+ }
+ });
+ }
+
+ public void buttonClick(ClickEvent event) {
+ Button source = event.getButton();
+
+ if (source == save) {
+ /* If the given input is not valid there is no point in continuing */
+ if (!isValid()) {
+ return;
+ }
+
+ commit();
+ if (newContactMode) {
+ /* We need to add the new person to the container */
+ Item addedItem = app.getDataSource().addItem(newPerson);
+ /*
+ * We must update the form to use the Item from our datasource
+ * as we are now in edit mode (no longer in add mode)
+ */
+ setItemDataSource(addedItem);
+
+ newContactMode = false;
+ }
+ setReadOnly(true);
+ } else if (source == cancel) {
+ if (newContactMode) {
+ newContactMode = false;
+ /* Clear the form and make it invisible */
+ setItemDataSource(null);
+ } else {
+ discard();
+ }
+ setReadOnly(true);
+ } else if (source == edit) {
+ setReadOnly(false);
+ }
+ }
+
+ @Override
+ public void setItemDataSource(Item newDataSource) {
+ newContactMode = false;
+
+ if (newDataSource != null) {
+ List<Object> orderedProperties = Arrays
+ .asList(PersonContainer.NATURAL_COL_ORDER);
+ super.setItemDataSource(newDataSource, orderedProperties);
+
+ setReadOnly(true);
+ getFooter().setVisible(true);
+ } else {
+ super.setItemDataSource(null);
+ getFooter().setVisible(false);
+ }
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ super.setReadOnly(readOnly);
+ save.setVisible(!readOnly);
+ cancel.setVisible(!readOnly);
+ edit.setVisible(readOnly);
+ }
+
+ public void addContact() {
+ // Create a temporary item for the form
+ newPerson = new Person();
+ setItemDataSource(new BeanItem(newPerson));
+ newContactMode = true;
+ setReadOnly(false);
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/tutorial/addressbook/ui/PersonList.java b/src/com/vaadin/demo/tutorial/addressbook/ui/PersonList.java
new file mode 100644
index 0000000000..f1bd945c38
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/ui/PersonList.java
@@ -0,0 +1,45 @@
+package com.vaadin.demo.tutorial.addressbook.ui;
+
+import com.vaadin.demo.tutorial.addressbook.AddressBookApplication;
+import com.vaadin.demo.tutorial.addressbook.data.Person;
+import com.vaadin.demo.tutorial.addressbook.data.PersonContainer;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Table;
+
+public class PersonList extends Table {
+ public PersonList(AddressBookApplication app) {
+ setSizeFull();
+ setContainerDataSource(app.getDataSource());
+
+ setVisibleColumns(PersonContainer.NATURAL_COL_ORDER);
+ setColumnHeaders(PersonContainer.COL_HEADERS_ENGLISH);
+
+ setColumnCollapsingAllowed(true);
+ setColumnReorderingAllowed(true);
+
+ /*
+ * Make table selectable, react immediatedly to user events, and pass
+ * events to the controller (our main application)
+ */
+ setSelectable(true);
+ setImmediate(true);
+ addListener((ValueChangeListener) app);
+ /* We don't want to allow users to de-select a row */
+ setNullSelectionAllowed(false);
+
+ // customize email column to have mailto: links using column generator
+ addGeneratedColumn("email", new ColumnGenerator() {
+ public Component generateCell(Table source, Object itemId,
+ Object columnId) {
+ Person p = (Person) itemId;
+ Link l = new Link();
+ l.setResource(new ExternalResource("mailto:" + p.getEmail()));
+ l.setCaption(p.getEmail());
+ return l;
+ }
+ });
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/tutorial/addressbook/ui/SearchView.java b/src/com/vaadin/demo/tutorial/addressbook/ui/SearchView.java
new file mode 100644
index 0000000000..dcf53b4fa9
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/ui/SearchView.java
@@ -0,0 +1,99 @@
+package com.vaadin.demo.tutorial.addressbook.ui;
+
+import com.vaadin.demo.tutorial.addressbook.AddressBookApplication;
+import com.vaadin.demo.tutorial.addressbook.data.PersonContainer;
+import com.vaadin.demo.tutorial.addressbook.data.SearchFilter;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Window.Notification;
+
+public class SearchView extends Panel {
+
+ private TextField tf;
+ private NativeSelect fieldToSearch;
+ private CheckBox saveSearch;
+ private TextField searchName;
+ private AddressBookApplication app;
+
+ public SearchView(final AddressBookApplication app) {
+ this.app = app;
+ addStyleName("view");
+
+ setCaption("Search contacts");
+ setSizeFull();
+
+ /* Use a FormLayout as main layout for this Panel */
+ FormLayout formLayout = new FormLayout();
+ setLayout(formLayout);
+
+ /* Create UI components */
+ tf = new TextField("Search term");
+ fieldToSearch = new NativeSelect("Field to search");
+ saveSearch = new CheckBox("Save search");
+ searchName = new TextField("Search name");
+ Button search = new Button("Search");
+
+ /* Initialize fieldToSearch */
+ for (int i = 0; i < PersonContainer.NATURAL_COL_ORDER.length; i++) {
+ fieldToSearch.addItem(PersonContainer.NATURAL_COL_ORDER[i]);
+ fieldToSearch.setItemCaption(PersonContainer.NATURAL_COL_ORDER[i],
+ PersonContainer.COL_HEADERS_ENGLISH[i]);
+ }
+
+ fieldToSearch.setValue("lastName");
+ fieldToSearch.setNullSelectionAllowed(false);
+
+ /* Initialize save checkbox */
+ saveSearch.setValue(true);
+ saveSearch.setImmediate(true);
+ saveSearch.addListener(new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ searchName.setVisible(event.getButton().booleanValue());
+ }
+ });
+
+ search.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ performSearch();
+ }
+
+ });
+
+ /* Add all the created components to the form */
+ addComponent(tf);
+ addComponent(fieldToSearch);
+ addComponent(saveSearch);
+ addComponent(searchName);
+ addComponent(search);
+ }
+
+ private void performSearch() {
+ String searchTerm = (String) tf.getValue();
+ if (searchTerm == null || searchTerm.equals("")) {
+ getWindow().showNotification("Search term cannot be empty!",
+ Notification.TYPE_WARNING_MESSAGE);
+ return;
+ }
+
+ SearchFilter searchFilter = new SearchFilter(fieldToSearch.getValue(),
+ searchTerm, (String) searchName.getValue());
+ if (saveSearch.booleanValue()) {
+ if (searchName.getValue() == null
+ || searchName.getValue().equals("")) {
+ getWindow().showNotification(
+ "Please enter a name for your search!",
+ Notification.TYPE_WARNING_MESSAGE);
+ return;
+ }
+ app.saveSearch(searchFilter);
+ }
+ app.search(searchFilter);
+ }
+
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/ui/SharingOptions.java b/src/com/vaadin/demo/tutorial/addressbook/ui/SharingOptions.java
new file mode 100644
index 0000000000..8ea22a4c7d
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/ui/SharingOptions.java
@@ -0,0 +1,39 @@
+package com.vaadin.demo.tutorial.addressbook.ui;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class SharingOptions extends Window {
+ public SharingOptions() {
+ /*
+ * Make the window modal, which will disable all other components while
+ * it is visible
+ */
+ setModal(true);
+
+ /* Make the sub window 50% the size of the browser window */
+ setWidth("50%");
+ /*
+ * Center the window both horizontally and vertically in the browser
+ * window
+ */
+ center();
+
+ setCaption("Sharing options");
+ addComponent(new Label(
+ "With these setting you can modify contact sharing "
+ + "options. (non-functional, example of modal dialog)"));
+ addComponent(new CheckBox("Gmail"));
+ addComponent(new CheckBox(".Mac"));
+ Button close = new Button("OK");
+ close.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ SharingOptions.this.close();
+ }
+ });
+ addComponent(close);
+ }
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/validators/EmailValidator.java b/src/com/vaadin/demo/tutorial/addressbook/validators/EmailValidator.java
new file mode 100644
index 0000000000..0c3068d976
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/validators/EmailValidator.java
@@ -0,0 +1,22 @@
+package com.vaadin.demo.tutorial.addressbook.validators;
+
+import com.vaadin.data.Validator;
+
+public class EmailValidator implements Validator {
+
+ public boolean isValid(Object value) {
+ if (value == null || !(value instanceof String)) {
+ return false;
+ }
+
+ return ((String) value).matches(".+@.+\\..+");
+ }
+
+ public void validate(Object value) throws InvalidValueException {
+ if (!isValid(value)) {
+ throw new InvalidValueException(
+ "Email must contain '@' and have full domain.");
+ }
+ }
+
+}
diff --git a/src/com/vaadin/demo/tutorial/addressbook/validators/PostalCodeValidator.java b/src/com/vaadin/demo/tutorial/addressbook/validators/PostalCodeValidator.java
new file mode 100644
index 0000000000..bd08ab6929
--- /dev/null
+++ b/src/com/vaadin/demo/tutorial/addressbook/validators/PostalCodeValidator.java
@@ -0,0 +1,22 @@
+package com.vaadin.demo.tutorial.addressbook.validators;
+
+import com.vaadin.data.Validator;
+
+public class PostalCodeValidator implements Validator {
+
+ public boolean isValid(Object value) {
+ if (value == null || !(value instanceof String)) {
+ return false;
+ }
+
+ return ((String) value).matches("[1-9][0-9]{4}");
+ }
+
+ public void validate(Object value) throws InvalidValueException {
+ if (!isValid(value)) {
+ throw new InvalidValueException(
+ "Postal code must be a five digit number and cannot start with a zero.");
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/demo/util/SampleCalendarDatabase.java b/src/com/vaadin/demo/util/SampleCalendarDatabase.java
new file mode 100644
index 0000000000..23c39a6e2e
--- /dev/null
+++ b/src/com/vaadin/demo/util/SampleCalendarDatabase.java
@@ -0,0 +1,168 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.util;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+
+/**
+ * Creates temporary database named toolkit with sample table named employee and
+ * populates it with data. By default we use HSQLDB. Ensure that you have
+ * hsqldb.jar under WEB-INF/lib directory. Database is will be created into
+ * memory.
+ *
+ * @author IT Mill Ltd.
+ *
+ */
+public class SampleCalendarDatabase {
+
+ public static final int ENTRYCOUNT = 100;
+
+ public static final String DB_TABLE_NAME = "calendar";
+ public static final String PROPERTY_ID_START = "EVENTSTART";
+ public static final String PROPERTY_ID_END = "EVENTEND";
+ public static final String PROPERTY_ID_TITLE = "TITLE";
+ public static final String PROPERTY_ID_NOTIME = "NOTIME";
+
+ private Connection connection = null;
+
+ private static final String[] titles = new String[] { "Meeting", "Dentist",
+ "Haircut", "Bank", "Birthday", "Library", "Rent", "Acme test",
+ "Party" };
+
+ /**
+ * Create temporary database.
+ *
+ */
+ public SampleCalendarDatabase() {
+ // connect to SQL database
+ connect();
+
+ // initialize SQL database
+ createTables();
+
+ // test by executing sample JDBC query
+ testDatabase();
+ }
+
+ /**
+ * Creates sample table named employee and populates it with data.Use the
+ * specified database connection.
+ *
+ * @param connection
+ */
+ public SampleCalendarDatabase(Connection connection) {
+ // initialize SQL database
+ createTables();
+
+ // test by executing sample JDBC query
+ testDatabase();
+ }
+
+ /**
+ * Connect to SQL database. In this sample we use HSQLDB and an toolkit
+ * named database in implicitly created into system memory.
+ *
+ */
+ private void connect() {
+ // use memory-Only Database
+ final String url = "jdbc:hsqldb:mem:toolkit";
+ try {
+ Class.forName("org.hsqldb.jdbcDriver").newInstance();
+ connection = DriverManager.getConnection(url, "sa", "");
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * use for SQL commands CREATE, DROP, INSERT and UPDATE
+ *
+ * @param expression
+ * @throws SQLException
+ */
+ public void update(String expression) throws SQLException {
+ Statement st = null;
+ st = connection.createStatement();
+ final int i = st.executeUpdate(expression);
+ if (i == -1) {
+ System.out.println("SampleDatabase error : " + expression);
+ }
+ st.close();
+ }
+
+ /**
+ * Create test table and few rows. Issue note: using capitalized column
+ * names as HSQLDB returns column names in capitalized form with this demo.
+ *
+ */
+ private void createTables() {
+ try {
+ String stmt = null;
+ stmt = "CREATE TABLE "
+ + DB_TABLE_NAME
+ + " ( ID INTEGER IDENTITY, TITLE VARCHAR(100), "
+ + "EVENTSTART DATETIME, EVENTEND DATETIME, NOTIME BOOLEAN )";
+ update(stmt);
+ for (int j = 0; j < ENTRYCOUNT; j++) {
+ final Timestamp start = new Timestamp(new java.util.Date()
+ .getTime());
+ start.setDate((int) ((Math.random() - 0.4) * 200));
+ start.setMinutes(0);
+ start.setHours(8 + (int) Math.random() * 12);
+ final Timestamp end = new Timestamp(start.getTime());
+ if (Math.random() < 0.7) {
+ long t = end.getTime();
+ final long hour = 60 * 60 * 1000;
+ t = t + hour + (Math.round(Math.random() * 3 * hour));
+ end.setTime(t);
+ }
+
+ stmt = "INSERT INTO "
+ + DB_TABLE_NAME
+ + "(TITLE, EVENTSTART, EVENTEND, NOTIME) VALUES ("
+ + "'"
+ + titles[(int) (Math.round(Math.random()
+ * (titles.length - 1)))] + "','" + start
+ + "','" + end + "'," + (Math.random() > 0.7) + ")";
+ update(stmt);
+ }
+ } catch (final SQLException e) {
+ if (e.toString().indexOf("Table already exists") == -1) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Test database connection with simple SELECT command.
+ *
+ */
+ private String testDatabase() {
+ String result = null;
+ try {
+ final Statement stmt = connection.createStatement(
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_UPDATABLE);
+ final ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM "
+ + DB_TABLE_NAME);
+ rs.next();
+ result = "rowcount for table test is " + rs.getObject(1).toString();
+ stmt.close();
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ public Connection getConnection() {
+ return connection;
+ }
+
+}
diff --git a/src/com/vaadin/demo/util/SampleDatabase.java b/src/com/vaadin/demo/util/SampleDatabase.java
new file mode 100644
index 0000000000..e9238d95da
--- /dev/null
+++ b/src/com/vaadin/demo/util/SampleDatabase.java
@@ -0,0 +1,173 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.util;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * Creates temporary database named toolkit with sample table named employee and
+ * populates it with data. By default we use HSQLDB. Ensure that you have
+ * hsqldb.jar under WEB-INF/lib directory. Database is will be created into
+ * memory.
+ *
+ * @author IT Mill Ltd.
+ *
+ */
+public class SampleDatabase {
+
+ public static final int ROWCOUNT = 1000;
+
+ private Connection connection = null;
+
+ private static final String[] firstnames = new String[] { "Amanda",
+ "Andrew", "Bill", "Frank", "Matt", "Xavier", "John", "Mary", "Joe",
+ "Gloria", "Marcus", "Belinda", "David", "Anthony", "Julian",
+ "Paul", "Carrie", "Susan", "Gregg", "Michael", "William", "Ethan",
+ "Thomas", "Oscar", "Norman", "Roy", "Sarah", "Jeff", "Jane",
+ "Peter", "Marc", "Josie", "Linus" };
+
+ private static final String[] lastnames = new String[] { "Torvalds",
+ "Smith", "Jones", "Beck", "Burton", "Bell", "Davis", "Burke",
+ "Bernard", "Hood", "Scott", "Smith", "Carter", "Roller", "Conrad",
+ "Martin", "Fisher", "Martell", "Freeman", "Hackman", "Jones",
+ "Harper", "Russek", "Johnson", "Sheridan", "Hill", "Parker",
+ "Foster", "Moss", "Fielding" };
+
+ private static final String[] titles = new String[] { "Project Manager",
+ "Marketing Manager", "Sales Manager", "Sales", "Trainer",
+ "Technical Support", "Account Manager", "Customer Support",
+ "Testing Engineer", "Software Designer", "Programmer", "Consultant" };
+
+ private static final String[] units = new String[] { "Tokyo",
+ "Mexico City", "Seoul", "New York", "Sao Paulo", "Bombay", "Delhi",
+ "Shanghai", "Los Angeles", "London", "Shanghai", "Sydney",
+ "Bangalore", "Hong Kong", "Madrid", "Milano", "Beijing", "Paris",
+ "Moscow", "Berlin", "Helsinki" };
+
+ /**
+ * Create temporary database.
+ *
+ */
+ public SampleDatabase() {
+ // connect to SQL database
+ connect();
+
+ // initialize SQL database
+ createTables();
+
+ // test by executing sample JDBC query
+ testDatabase();
+ }
+
+ /**
+ * Creates sample table named employee and populates it with data.Use the
+ * specified database connection.
+ *
+ * @param connection
+ */
+ public SampleDatabase(Connection connection) {
+ // initialize SQL database
+ createTables();
+
+ // test by executing sample JDBC query
+ testDatabase();
+ }
+
+ /**
+ * Connect to SQL database. In this sample we use HSQLDB and an toolkit
+ * named database in implicitly created into system memory.
+ *
+ */
+ private void connect() {
+ // use memory-Only Database
+ final String url = "jdbc:hsqldb:mem:toolkit";
+ try {
+ Class.forName("org.hsqldb.jdbcDriver").newInstance();
+ connection = DriverManager.getConnection(url, "sa", "");
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * use for SQL commands CREATE, DROP, INSERT and UPDATE
+ *
+ * @param expression
+ * @throws SQLException
+ */
+ public void update(String expression) throws SQLException {
+ Statement st = null;
+ st = connection.createStatement();
+ final int i = st.executeUpdate(expression);
+ if (i == -1) {
+ throw new SQLException("Database error : " + expression);
+ }
+ st.close();
+ }
+
+ /**
+ * Create test table and few rows. Issue note: using capitalized column
+ * names as HSQLDB returns column names in capitalized form with this demo.
+ *
+ */
+ private void createTables() {
+ try {
+ String stmt = null;
+ stmt = "CREATE TABLE employee ( ID INTEGER IDENTITY, FIRSTNAME VARCHAR(100), "
+ + "LASTNAME VARCHAR(100), TITLE VARCHAR(100), UNIT VARCHAR(100) )";
+ update(stmt);
+ for (int j = 0; j < ROWCOUNT; j++) {
+ stmt = "INSERT INTO employee(FIRSTNAME, LASTNAME, TITLE, UNIT) VALUES ("
+ + "'"
+ + firstnames[(int) (Math.random() * (firstnames.length - 1))]
+ + "',"
+ + "'"
+ + lastnames[(int) (Math.random() * (lastnames.length - 1))]
+ + "',"
+ + "'"
+ + titles[(int) (Math.random() * (titles.length - 1))]
+ + "',"
+ + "'"
+ + units[(int) (Math.random() * (units.length - 1))]
+ + "'" + ")";
+ update(stmt);
+ }
+ } catch (final SQLException e) {
+ if (e.toString().indexOf("Table already exists") == -1) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Test database connection with simple SELECT command.
+ *
+ */
+ private String testDatabase() {
+ String result = null;
+ try {
+ final Statement stmt = connection.createStatement(
+ ResultSet.TYPE_SCROLL_INSENSITIVE,
+ ResultSet.CONCUR_UPDATABLE);
+ final ResultSet rs = stmt
+ .executeQuery("SELECT COUNT(*) FROM employee");
+ rs.next();
+ result = "rowcount for table test is " + rs.getObject(1).toString();
+ stmt.close();
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ public Connection getConnection() {
+ return connection;
+ }
+
+}
diff --git a/src/com/vaadin/demo/util/SampleDirectory.java b/src/com/vaadin/demo/util/SampleDirectory.java
new file mode 100644
index 0000000000..2e4c785024
--- /dev/null
+++ b/src/com/vaadin/demo/util/SampleDirectory.java
@@ -0,0 +1,73 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.util;
+
+import java.io.File;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.SystemError;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+
+/**
+ * Provides sample directory based on application directory. If this fails then
+ * sampleDirectory property is read. If no sample directory is resolved, then a
+ * panel displaying error message is added to main window.
+ *
+ * @author IT Mill Ltd.
+ *
+ */
+public class SampleDirectory {
+
+ /**
+ * Get sample directory.
+ *
+ * @param application
+ * @return file pointing to sample directory
+ */
+ public static File getDirectory(Application application) {
+ String errorMessage = "Access to application "
+ + "context base directory failed, "
+ + "possible security constraint with Application "
+ + "Server or Servlet Container.<br />";
+ File file = application.getContext().getBaseDirectory();
+ if ((file == null) || (!file.canRead())
+ || (file.getAbsolutePath() == null)) {
+ // cannot access example directory, possible security issue with
+ // Application Server or Servlet Container
+ // Try to read sample directory from web.xml parameter
+ if (application.getProperty("sampleDirectory") != null) {
+ file = new File(application.getProperty("sampleDirectory"));
+ if ((file != null) && (file.canRead())
+ && (file.getAbsolutePath() != null)) {
+ // Success using property
+ return file;
+ }
+ // Failure using property
+ errorMessage += "Failed also to access sample directory <b>["
+ + application.getProperty("sampleDirectory")
+ + "]</b> defined in <b>sampleDirectory property</b>.";
+ } else {
+ // Failure using application context base dir, no property set
+ errorMessage += "<b>Note: </b>You can set this manually in "
+ + "web.xml by defining " + "sampleDirectory property.";
+ }
+ } else {
+ // Success using application context base dir
+ return file;
+ }
+ // Add failure notification as an Panel to main window
+ final Panel errorPanel = new Panel("Demo application error");
+ errorPanel.setStyle("strong");
+ errorPanel.setComponentError(new SystemError(
+ "Cannot provide sample directory"));
+ errorPanel.addComponent(new Label(errorMessage, Label.CONTENT_XHTML));
+ // Remove all components from applications main window
+ application.getMainWindow().getLayout().removeAllComponents();
+ // Add error panel
+ application.getMainWindow().getLayout().addComponent(errorPanel);
+ return null;
+ }
+}