summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/vaadin/Application.java1292
-rw-r--r--src/com/vaadin/RootRequiresMoreInformationException.java25
-rw-r--r--src/com/vaadin/annotations/EagerInit.java30
-rw-r--r--src/com/vaadin/annotations/Theme.java24
-rw-r--r--src/com/vaadin/annotations/Widgetset.java25
-rw-r--r--src/com/vaadin/data/Buffered.java83
-rw-r--r--src/com/vaadin/data/Container.java4
-rw-r--r--src/com/vaadin/data/Item.java2
-rw-r--r--src/com/vaadin/data/Property.java148
-rw-r--r--src/com/vaadin/data/Validator.java33
-rw-r--r--src/com/vaadin/data/fieldgroup/BeanFieldGroup.java157
-rw-r--r--src/com/vaadin/data/fieldgroup/Caption.java15
-rw-r--r--src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java156
-rw-r--r--src/com/vaadin/data/fieldgroup/FieldGroup.java978
-rw-r--r--src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java31
-rw-r--r--src/com/vaadin/data/fieldgroup/PropertyId.java15
-rw-r--r--src/com/vaadin/data/util/AbstractBeanContainer.java53
-rw-r--r--src/com/vaadin/data/util/AbstractProperty.java23
-rw-r--r--src/com/vaadin/data/util/BeanItem.java47
-rw-r--r--src/com/vaadin/data/util/ContainerHierarchicalWrapper.java2
-rw-r--r--src/com/vaadin/data/util/ContainerOrderedWrapper.java2
-rw-r--r--src/com/vaadin/data/util/DefaultItemSorter.java4
-rw-r--r--src/com/vaadin/data/util/FilesystemContainer.java4
-rw-r--r--src/com/vaadin/data/util/IndexedContainer.java54
-rw-r--r--src/com/vaadin/data/util/MethodProperty.java76
-rw-r--r--src/com/vaadin/data/util/MethodPropertyDescriptor.java4
-rw-r--r--src/com/vaadin/data/util/NestedMethodProperty.java34
-rw-r--r--src/com/vaadin/data/util/NestedPropertyDescriptor.java7
-rw-r--r--src/com/vaadin/data/util/ObjectProperty.java58
-rw-r--r--src/com/vaadin/data/util/PropertyFormatter.java54
-rw-r--r--src/com/vaadin/data/util/PropertysetItem.java10
-rw-r--r--src/com/vaadin/data/util/QueryContainer.java7
-rw-r--r--src/com/vaadin/data/util/TextFileProperty.java6
-rw-r--r--src/com/vaadin/data/util/TransactionalPropertyWrapper.java107
-rw-r--r--src/com/vaadin/data/util/VaadinPropertyDescriptor.java4
-rw-r--r--src/com/vaadin/data/util/converter/Converter.java159
-rw-r--r--src/com/vaadin/data/util/converter/ConverterFactory.java23
-rw-r--r--src/com/vaadin/data/util/converter/DateToLongConverter.java68
-rw-r--r--src/com/vaadin/data/util/converter/DefaultConverterFactory.java100
-rw-r--r--src/com/vaadin/data/util/converter/ReverseConverter.java80
-rw-r--r--src/com/vaadin/data/util/converter/StringToBooleanConverter.java104
-rw-r--r--src/com/vaadin/data/util/converter/StringToDateConverter.java108
-rw-r--r--src/com/vaadin/data/util/converter/StringToDoubleConverter.java103
-rw-r--r--src/com/vaadin/data/util/converter/StringToIntegerConverter.java84
-rw-r--r--src/com/vaadin/data/util/converter/StringToNumberConverter.java107
-rw-r--r--src/com/vaadin/data/util/filter/Compare.java2
-rw-r--r--src/com/vaadin/data/util/filter/IsNull.java2
-rw-r--r--src/com/vaadin/data/util/filter/SimpleStringFilter.java12
-rw-r--r--src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java32
-rw-r--r--src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java4
-rw-r--r--src/com/vaadin/data/util/sqlcontainer/RowItem.java5
-rw-r--r--src/com/vaadin/data/util/sqlcontainer/SQLContainer.java6
-rw-r--r--src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java56
-rw-r--r--src/com/vaadin/data/validator/AbstractStringValidator.java42
-rw-r--r--src/com/vaadin/data/validator/AbstractValidator.java71
-rw-r--r--src/com/vaadin/data/validator/BeanValidator.java173
-rw-r--r--src/com/vaadin/data/validator/CompositeValidator.java131
-rw-r--r--src/com/vaadin/data/validator/DateRangeValidator.java51
-rw-r--r--src/com/vaadin/data/validator/DoubleRangeValidator.java36
-rw-r--r--src/com/vaadin/data/validator/DoubleValidator.java20
-rw-r--r--src/com/vaadin/data/validator/IntegerRangeValidator.java37
-rw-r--r--src/com/vaadin/data/validator/IntegerValidator.java19
-rw-r--r--src/com/vaadin/data/validator/NullValidator.java11
-rw-r--r--src/com/vaadin/data/validator/RangeValidator.java186
-rw-r--r--src/com/vaadin/data/validator/RegexpValidator.java5
-rw-r--r--src/com/vaadin/data/validator/StringLengthValidator.java57
-rw-r--r--src/com/vaadin/external/json/JSONArray.java963
-rw-r--r--src/com/vaadin/external/json/JSONException.java28
-rw-r--r--src/com/vaadin/external/json/JSONObject.java1693
-rw-r--r--src/com/vaadin/external/json/JSONString.java21
-rw-r--r--src/com/vaadin/external/json/JSONStringer.java78
-rw-r--r--src/com/vaadin/external/json/JSONTokener.java451
-rw-r--r--src/com/vaadin/external/json/JSONWriter.java355
-rw-r--r--src/com/vaadin/external/json/README68
-rw-r--r--src/com/vaadin/terminal/CombinedRequest.java167
-rw-r--r--src/com/vaadin/terminal/CompositeErrorMessage.java26
-rw-r--r--src/com/vaadin/terminal/DeploymentConfiguration.java77
-rw-r--r--src/com/vaadin/terminal/DownloadStream.java129
-rw-r--r--src/com/vaadin/terminal/ErrorMessage.java83
-rw-r--r--src/com/vaadin/terminal/ParameterHandler.java59
-rw-r--r--src/com/vaadin/terminal/RequestHandler.java36
-rw-r--r--src/com/vaadin/terminal/Sizeable.java204
-rw-r--r--src/com/vaadin/terminal/SystemError.java6
-rw-r--r--src/com/vaadin/terminal/URIHandler.java48
-rw-r--r--src/com/vaadin/terminal/UserError.java94
-rw-r--r--src/com/vaadin/terminal/WrappedRequest.java277
-rw-r--r--src/com/vaadin/terminal/WrappedResponse.java147
-rw-r--r--src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml12
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java462
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConnection.java791
-rw-r--r--src/com/vaadin/terminal/gwt/client/BrowserInfo.java109
-rw-r--r--src/com/vaadin/terminal/gwt/client/ComponentDetail.java22
-rw-r--r--src/com/vaadin/terminal/gwt/client/ComponentLocator.java17
-rw-r--r--src/com/vaadin/terminal/gwt/client/Console.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/Container.java25
-rw-r--r--src/com/vaadin/terminal/gwt/client/EventHelper.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java192
-rw-r--r--src/com/vaadin/terminal/gwt/client/NullConsole.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/Paintable.java18
-rw-r--r--src/com/vaadin/terminal/gwt/client/UIDL.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/Util.java244
-rw-r--r--src/com/vaadin/terminal/gwt/client/VBrowserDetails.java51
-rw-r--r--src/com/vaadin/terminal/gwt/client/VCaption.java21
-rw-r--r--src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/VConsole.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/VDebugConsole.java27
-rw-r--r--src/com/vaadin/terminal/gwt/client/VPaintable.java74
-rw-r--r--src/com/vaadin/terminal/gwt/client/VPaintableMap.java403
-rw-r--r--src/com/vaadin/terminal/gwt/client/VPaintableWidget.java31
-rw-r--r--src/com/vaadin/terminal/gwt/client/VPaintableWidgetContainer.java45
-rw-r--r--src/com/vaadin/terminal/gwt/client/VTooltip.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java22
-rw-r--r--src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/WidgetMap.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/WidgetSet.java75
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java18
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java56
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java16
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/Icon.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java12
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java19
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/Table.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java162
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayoutPaintable.java84
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java103
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidgetContainer.java17
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java (renamed from src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java)167
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanelPaintable.java140
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAccordion.java146
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAccordionPaintable.java68
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAudio.java25
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAudioPaintable.java37
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VButton.java110
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VButtonPaintable.java91
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java52
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java115
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCheckBoxPaintable.java96
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java118
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCssLayoutPaintable.java61
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java68
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCustomComponentPaintable.java79
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java116
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCustomLayoutPaintable.java87
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDateField.java96
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java70
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendarPaintable.java101
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDateFieldPaintable.java106
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java95
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperIE.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperPaintable.java71
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java182
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VEmbeddedPaintable.java198
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java337
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VFilterSelectPaintable.java244
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VForm.java185
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java126
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VFormLayoutPaintable.java39
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VFormPaintable.java173
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java269
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VGridLayoutPaintable.java193
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayoutPaintable.java17
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VHorizontalSplitPanelPaintable.java13
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VLabel.java135
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VLink.java98
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VLinkPaintable.java100
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VListSelect.java20
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VListSelectPaintable.java21
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java115
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VMediaBasePaintable.java109
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java273
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java161
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java117
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VNativeButtonPaintable.java86
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java12
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VNativeSelectPaintable.java21
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java65
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java98
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBasePaintable.java103
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOptionGroupPaintable.java71
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java287
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOrderedLayoutPaintable.java254
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOverlay.java32
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPanel.java224
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPanelPaintable.java175
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPasswordFieldPaintable.java28
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java120
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPopupCalendarPaintable.java138
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPopupView.java111
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPopupViewPaintable.java104
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java47
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VProgressIndicatorPaintable.java65
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java463
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java254
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VSlider.java122
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VSliderPaintable.java78
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java446
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java171
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java78
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTabsheetBasePaintable.java96
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTabsheetPaintable.java82
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextArea.java16
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextAreaPaintable.java38
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextField.java190
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextFieldPaintable.java124
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java84
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextualDatePaintable.java58
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTree.java427
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTreePaintable.java228
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java94
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java101
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java40
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTwinColSelectPaintable.java34
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java32
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VUnknownComponentPaintable.java52
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VUpload.java70
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VUploadPaintable.java62
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java85
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VVerticalLayoutPaintable.java17
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VVerticalSplitPanelPaintable.java12
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VVideo.java24
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VVideoPaintable.java38
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VView.java381
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VViewPaintable.java331
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VWindow.java392
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VWindowPaintable.java296
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java19
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java11
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java13
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java70
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/label/VLabelPaintable.java71
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java100
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayoutPaintable.java81
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java79
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java78
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextAreaPaintable.java76
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java1157
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java1051
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java766
-rw-r--r--src/com/vaadin/terminal/gwt/server/ApplicationPortlet.java250
-rw-r--r--src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java20
-rw-r--r--src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java54
-rw-r--r--src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java72
-rw-r--r--src/com/vaadin/terminal/gwt/server/ApplicationServlet.java23
-rw-r--r--src/com/vaadin/terminal/gwt/server/BootstrapHandler.java602
-rw-r--r--src/com/vaadin/terminal/gwt/server/CommunicationManager.java320
-rw-r--r--src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java39
-rw-r--r--src/com/vaadin/terminal/gwt/server/Constants.java1
-rw-r--r--src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java4
-rw-r--r--src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java186
-rw-r--r--src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java52
-rw-r--r--src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java358
-rw-r--r--src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java73
-rw-r--r--src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java88
-rw-r--r--src/com/vaadin/terminal/gwt/server/WebBrowser.java80
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java109
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java73
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java175
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java102
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java5
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java75
-rw-r--r--src/com/vaadin/tools/ReflectTools.java86
-rw-r--r--src/com/vaadin/ui/AbsoluteLayout.java80
-rw-r--r--src/com/vaadin/ui/AbstractComponent.java219
-rw-r--r--src/com/vaadin/ui/AbstractComponentContainer.java16
-rw-r--r--src/com/vaadin/ui/AbstractField.java771
-rw-r--r--src/com/vaadin/ui/AbstractMedia.java26
-rw-r--r--src/com/vaadin/ui/AbstractSelect.java152
-rw-r--r--src/com/vaadin/ui/AbstractSplitPanel.java18
-rw-r--r--src/com/vaadin/ui/AbstractTextField.java19
-rw-r--r--src/com/vaadin/ui/Accordion.java5
-rw-r--r--src/com/vaadin/ui/Audio.java4
-rw-r--r--src/com/vaadin/ui/BaseFieldFactory.java90
-rw-r--r--src/com/vaadin/ui/Button.java250
-rw-r--r--src/com/vaadin/ui/CheckBox.java158
-rw-r--r--src/com/vaadin/ui/ClientWidget.java4
-rw-r--r--src/com/vaadin/ui/ComboBox.java3
-rw-r--r--src/com/vaadin/ui/Component.java6
-rw-r--r--src/com/vaadin/ui/CssLayout.java4
-rw-r--r--src/com/vaadin/ui/CustomComponent.java43
-rw-r--r--src/com/vaadin/ui/CustomField.java252
-rw-r--r--src/com/vaadin/ui/CustomLayout.java4
-rw-r--r--src/com/vaadin/ui/DateField.java356
-rw-r--r--src/com/vaadin/ui/DefaultFieldFactory.java17
-rw-r--r--src/com/vaadin/ui/DragAndDropWrapper.java3
-rw-r--r--src/com/vaadin/ui/Embedded.java6
-rw-r--r--src/com/vaadin/ui/ExpandLayout.java101
-rw-r--r--src/com/vaadin/ui/Field.java26
-rw-r--r--src/com/vaadin/ui/FieldFactory.java46
-rw-r--r--src/com/vaadin/ui/Form.java117
-rw-r--r--src/com/vaadin/ui/FormFieldFactory.java2
-rw-r--r--src/com/vaadin/ui/FormLayout.java8
-rw-r--r--src/com/vaadin/ui/GridLayout.java4
-rw-r--r--src/com/vaadin/ui/HorizontalLayout.java4
-rw-r--r--src/com/vaadin/ui/HorizontalSplitPanel.java4
-rw-r--r--src/com/vaadin/ui/InlineDateField.java4
-rw-r--r--src/com/vaadin/ui/Label.java331
-rw-r--r--src/com/vaadin/ui/Link.java10
-rw-r--r--src/com/vaadin/ui/ListSelect.java4
-rw-r--r--src/com/vaadin/ui/LoginForm.java70
-rw-r--r--src/com/vaadin/ui/MenuBar.java70
-rw-r--r--src/com/vaadin/ui/NativeButton.java37
-rw-r--r--src/com/vaadin/ui/NativeSelect.java4
-rw-r--r--src/com/vaadin/ui/Notification.java321
-rw-r--r--src/com/vaadin/ui/OptionGroup.java3
-rw-r--r--src/com/vaadin/ui/OrderedLayout.java128
-rw-r--r--src/com/vaadin/ui/Panel.java7
-rw-r--r--src/com/vaadin/ui/PasswordField.java4
-rw-r--r--src/com/vaadin/ui/PopupView.java4
-rw-r--r--src/com/vaadin/ui/ProgressIndicator.java26
-rw-r--r--src/com/vaadin/ui/RichTextArea.java15
-rw-r--r--src/com/vaadin/ui/Root.java1539
-rw-r--r--src/com/vaadin/ui/Select.java4
-rw-r--r--src/com/vaadin/ui/Slider.java193
-rw-r--r--src/com/vaadin/ui/SplitPanel.java114
-rw-r--r--src/com/vaadin/ui/TabSheet.java4
-rw-r--r--src/com/vaadin/ui/Table.java492
-rw-r--r--src/com/vaadin/ui/TableFieldFactory.java2
-rw-r--r--src/com/vaadin/ui/TextArea.java4
-rw-r--r--src/com/vaadin/ui/TextField.java204
-rw-r--r--src/com/vaadin/ui/Tree.java3
-rw-r--r--src/com/vaadin/ui/TreeTable.java7
-rw-r--r--src/com/vaadin/ui/TwinColSelect.java3
-rw-r--r--src/com/vaadin/ui/Upload.java4
-rw-r--r--src/com/vaadin/ui/UriFragmentUtility.java153
-rw-r--r--src/com/vaadin/ui/VerticalLayout.java4
-rw-r--r--src/com/vaadin/ui/VerticalSplitPanel.java4
-rw-r--r--src/com/vaadin/ui/Video.java6
-rw-r--r--src/com/vaadin/ui/Window.java1558
337 files changed, 24108 insertions, 16495 deletions
diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java
index 9fb4cfe7fa..e426ea3085 100644
--- a/src/com/vaadin/Application.java
+++ b/src/com/vaadin/Application.java
@@ -4,35 +4,56 @@
package com.vaadin;
+import java.io.IOException;
import java.io.Serializable;
+import java.lang.annotation.Annotation;
import java.net.SocketException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.EventObject;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Hashtable;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Properties;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.vaadin.annotations.EagerInit;
+import com.vaadin.annotations.Theme;
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.data.util.converter.Converter;
+import com.vaadin.data.util.converter.ConverterFactory;
+import com.vaadin.data.util.converter.DefaultConverterFactory;
import com.vaadin.service.ApplicationContext;
import com.vaadin.terminal.ApplicationResource;
-import com.vaadin.terminal.DownloadStream;
+import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.ErrorMessage;
-import com.vaadin.terminal.ParameterHandler;
+import com.vaadin.terminal.RequestHandler;
import com.vaadin.terminal.SystemError;
import com.vaadin.terminal.Terminal;
-import com.vaadin.terminal.URIHandler;
import com.vaadin.terminal.VariableOwner;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedRequest.BrowserDetails;
+import com.vaadin.terminal.WrappedResponse;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;
import com.vaadin.terminal.gwt.server.ChangeVariablesErrorEvent;
-import com.vaadin.terminal.gwt.server.PortletApplicationContext;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.AbstractField;
+import com.vaadin.ui.Root;
+import com.vaadin.ui.Table;
import com.vaadin.ui.Window;
/**
@@ -89,17 +110,223 @@ import com.vaadin.ui.Window;
* @since 3.0
*/
@SuppressWarnings("serial")
-public abstract class Application implements URIHandler,
- Terminal.ErrorListener, Serializable {
+public class Application implements Terminal.ErrorListener, Serializable {
- private final static Logger logger = Logger.getLogger(Application.class
- .getName());
+ /**
+ * The name of the parameter that is by default used in e.g. web.xml to
+ * define the name of the default {@link Root} class.
+ */
+ public static final String ROOT_PARAMETER = "root";
/**
- * Id use for the next window that is opened. Access to this must be
- * synchronized.
+ * A special application designed to help migrating applications from Vaadin
+ * 6 to Vaadin 7. The legacy application supports setting a main window,
+ * adding additional browser level windows and defining the theme for the
+ * entire application.
+ *
+ * @deprecated This class is only intended to ease migration and should not
+ * be used for new projects.
+ *
+ * @since 7.0
*/
- private int nextWindowId = 1;
+ @Deprecated
+ public static class LegacyApplication extends Application {
+ /**
+ * Ignore initial / and then get everything up to the next /
+ */
+ private static final Pattern WINDOW_NAME_PATTERN = Pattern
+ .compile("^/?([^/]+).*");
+
+ private Root.LegacyWindow mainWindow;
+ private String theme;
+
+ private Map<String, Root.LegacyWindow> legacyRootNames = new HashMap<String, Root.LegacyWindow>();
+
+ /**
+ * Sets the main window of this application. Setting window as a main
+ * window of this application also adds the window to this application.
+ *
+ * @param mainWindow
+ * the root to set as the default window
+ */
+ public void setMainWindow(Root.LegacyWindow mainWindow) {
+ if (this.mainWindow != null) {
+ throw new IllegalStateException(
+ "mainWindow has already been set");
+ }
+ if (mainWindow.getApplication() == null) {
+ mainWindow.setApplication(this);
+ } else if (mainWindow.getApplication() != this) {
+ throw new IllegalStateException(
+ "mainWindow is attached to another application");
+ }
+ this.mainWindow = mainWindow;
+ }
+
+ /**
+ * Gets the mainWindow of the application.
+ *
+ * <p>
+ * The main window is the window attached to the application URL (
+ * {@link #getURL()}) and thus which is show by default to the user.
+ * </p>
+ * <p>
+ * Note that each application must have at least one main window.
+ * </p>
+ *
+ * @return the root used as the default window
+ */
+ public Root.LegacyWindow getMainWindow() {
+ return mainWindow;
+ }
+
+ /**
+ * This implementation simulates the way of finding a window for a
+ * request by extracting a window name from the requested path and
+ * passes that name to {@link #getWindow(String)}.
+ *
+ * {@inheritDoc}
+ *
+ * @see #getWindow(String)
+ * @see Application#getRoot(WrappedRequest)
+ */
+ @Override
+ public Root.LegacyWindow getRoot(WrappedRequest request) {
+ String pathInfo = request.getRequestPathInfo();
+ String name = null;
+ if (pathInfo != null && pathInfo.length() > 0) {
+ Matcher matcher = WINDOW_NAME_PATTERN.matcher(pathInfo);
+ if (matcher.matches()) {
+ // Skip the initial slash
+ name = matcher.group(1);
+ }
+ }
+ Root.LegacyWindow window = getWindow(name);
+ if (window != null) {
+ return window;
+ }
+ return mainWindow;
+ }
+
+ /**
+ * Sets the application's theme.
+ * <p>
+ * Note that this theme can be overridden for a specific root with
+ * {@link Application#getThemeForRoot(Root)}. Setting theme to be
+ * <code>null</code> selects the default theme. For the available theme
+ * names, see the contents of the VAADIN/themes directory.
+ * </p>
+ *
+ * @param theme
+ * the new theme for this application.
+ */
+ public void setTheme(String theme) {
+ this.theme = theme;
+ }
+
+ /**
+ * Gets the application's theme. The application's theme is the default
+ * theme used by all the roots for which a theme is not explicitly
+ * defined. If the application theme is not explicitly set,
+ * <code>null</code> is returned.
+ *
+ * @return the name of the application's theme.
+ */
+ public String getTheme() {
+ return theme;
+ }
+
+ /**
+ * This implementation returns the theme that has been set using
+ * {@link #setTheme(String)}
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getThemeForRoot(Root root) {
+ return theme;
+ }
+
+ /**
+ * <p>
+ * Gets a root by name. Returns <code>null</code> if the application is
+ * not running or it does not contain a window corresponding to the
+ * name.
+ * </p>
+ *
+ * @param name
+ * the name of the requested window
+ * @return a root corresponding to the name, or <code>null</code> to use
+ * the default window
+ */
+ public Root.LegacyWindow getWindow(String name) {
+ return legacyRootNames.get(name);
+ }
+
+ /**
+ * Counter to get unique names for windows with no explicit name
+ */
+ private int namelessRootIndex = 0;
+
+ /**
+ * Adds a new browser level window to this application. Please note that
+ * Root doesn't have a name that is used in the URL - to add a named
+ * window you should instead use {@link #addWindow(Root, String)}
+ *
+ * @param root
+ * the root window to add to the application
+ * @return returns the name that has been assigned to the window
+ *
+ * @see #addWindow(Root, String)
+ */
+ public void addWindow(Root.LegacyWindow root) {
+ if (root.getName() == null) {
+ String name = Integer.toString(namelessRootIndex++);
+ root.setName(name);
+ }
+
+ legacyRootNames.put(root.getName(), root);
+ root.setApplication(this);
+ }
+
+ /**
+ * Removes the specified window from the application. This also removes
+ * all name mappings for the window (see
+ * {@link #addWindow(Root, String) and #getWindowName(Root)}.
+ *
+ * <p>
+ * Note that removing window from the application does not close the
+ * browser window - the window is only removed from the server-side.
+ * </p>
+ *
+ * @param root
+ * the root to remove
+ */
+ public void removeWindow(Root.LegacyWindow root) {
+ for (Entry<String, Root.LegacyWindow> entry : legacyRootNames
+ .entrySet()) {
+ if (entry.getValue() == root) {
+ legacyRootNames.remove(entry.getKey());
+ }
+ }
+ }
+
+ /**
+ * Gets the set of windows contained by the application.
+ *
+ * <p>
+ * Note that the returned set of windows can not be modified.
+ * </p>
+ *
+ * @return the unmodifiable collection of windows.
+ */
+ public Collection<Root.LegacyWindow> getWindows() {
+ return Collections.unmodifiableCollection(legacyRootNames.values());
+ }
+ }
+
+ private final static Logger logger = Logger.getLogger(Application.class
+ .getName());
/**
* Application context the application is running in.
@@ -112,26 +339,11 @@ public abstract class Application implements URIHandler,
private Object user;
/**
- * Mapping from window name to window instance.
- */
- private final Hashtable<String, Window> windows = new Hashtable<String, Window>();
-
- /**
- * Main window of the application.
- */
- private Window mainWindow = null;
-
- /**
* The application's URL.
*/
private URL applicationUrl;
/**
- * Name of the theme currently used by the application.
- */
- private String theme = null;
-
- /**
* Application status.
*/
private volatile boolean applicationIsRunning = false;
@@ -152,16 +364,6 @@ public abstract class Application implements URIHandler,
private LinkedList<UserChangeListener> userChangeListeners = null;
/**
- * Window attach listeners.
- */
- private LinkedList<WindowAttachListener> windowAttachListeners = null;
-
- /**
- * Window detach listeners.
- */
- private LinkedList<WindowDetachListener> windowDetachListeners = null;
-
- /**
* Application resource mapping: key <-> resource.
*/
private final Hashtable<ApplicationResource, String> resourceKeyMap = new Hashtable<ApplicationResource, String>();
@@ -189,237 +391,28 @@ public abstract class Application implements URIHandler,
private Terminal.ErrorListener errorHandler = this;
/**
- * <p>
- * Gets a window by name. Returns <code>null</code> if the application is
- * not running or it does not contain a window corresponding to the name.
- * </p>
- *
- * <p>
- * All windows can be referenced by their names in url
- * <code>http://host:port/foo/bar/</code> where
- * <code>http://host:port/foo/</code> is the application url as returned by
- * getURL() and <code>bar</code> is the name of the window.
- * </p>
- *
- * <p>
- * One should note that this method can, as a side effect create new windows
- * if needed by the application. This can be achieved by overriding the
- * default implementation.
- * </p>
- *
- * <p>
- * If for some reason user opens another window with same url that is
- * already open, the name is modified by adding a "_N" postfix to the name,
- * where N is a running number starting from 1. One can decide to create
- * another window-object for those windows (recommended) or to discard the
- * postfix. If the user has two browser windows pointing to the same
- * window-object on server, synchronization errors are likely to occur.
- * </p>
- *
- * <p>
- * If no browser-level windowing is used, all defaults are fine and this
- * method can be left as is. In case browser-level windows are needed, it is
- * recommended to create new window-objects on this method from their names
- * if the super.getWindow() does not find existing windows. See below for
- * implementation example: <code><pre>
- // If we already have the requested window, use it
- Window w = super.getWindow(name);
- if (w == null) {
- // If no window found, create it
- w = new Window(name);
- // set windows name to the one requested
- w.setName(name);
- // add it to this application
- addWindow(w);
- // ensure use of window specific url
- w.open(new ExternalResource(w.getURL().toString()));
- // add some content
- w.addComponent(new Label("Test window"));
- }
- return w;</pre></code>
- * </p>
- *
- * <p>
- * <strong>Note</strong> that all returned Window objects must be added to
- * this application instance.
- *
- * <p>
- * The method should return null if the window does not exists (and is not
- * created as a side-effect) or if the application is not running anymore.
- * </p>
- *
- * @param name
- * the name of the window.
- * @return the window associated with the given URI or <code>null</code>
+ * The converter factory that is used to provide default converters for the
+ * application.
*/
- public Window getWindow(String name) {
+ private ConverterFactory converterFactory = new DefaultConverterFactory();
- // For closed app, do not give any windows
- if (!isRunning()) {
- return null;
- }
+ private LinkedList<RequestHandler> requestHandlers = new LinkedList<RequestHandler>();
- // Gets the window by name
- final Window window = windows.get(name);
+ private int nextRootId = 0;
+ private Map<Integer, Root> roots = new HashMap<Integer, Root>();
- return window;
- }
+ private boolean productionMode = true;
- /**
- * Adds a new window to the application.
- *
- * <p>
- * This implicitly invokes the
- * {@link com.vaadin.ui.Window#setApplication(Application)} method.
- * </p>
- *
- * <p>
- * Note that all application-level windows can be accessed by their names in
- * url <code>http://host:port/foo/bar/</code> where
- * <code>http://host:port/foo/</code> is the application url as returned by
- * getURL() and <code>bar</code> is the name of the window. Also note that
- * not all windows should be added to application - one can also add windows
- * inside other windows - these windows show as smaller windows inside those
- * windows.
- * </p>
- *
- * @param window
- * the new <code>Window</code> to add. If the name of the window
- * is <code>null</code>, an unique name is automatically given
- * for the window.
- * @throws IllegalArgumentException
- * if a window with the same name as the new window already
- * exists in the application.
- * @throws NullPointerException
- * if the given <code>Window</code> is <code>null</code>.
- */
- public void addWindow(Window window) throws IllegalArgumentException,
- NullPointerException {
-
- // Nulls can not be added to application
- if (window == null) {
- return;
- }
-
- // Check that one is not adding a sub-window to application
- if (window.getParent() != null) {
- throw new IllegalArgumentException(
- "Window was already added inside another window"
- + " - it can not be added to application also.");
- }
-
- // Gets the naming proposal from window
- String name = window.getName();
-
- // Checks that the application does not already contain
- // window having the same name
- if (name != null && windows.containsKey(name)) {
-
- // If the window is already added
- if (window == windows.get(name)) {
- return;
- }
-
- // Otherwise complain
- throw new IllegalArgumentException("Window with name '"
- + window.getName()
- + "' is already present in the application");
- }
-
- // If the name of the window is null, the window is automatically named
- if (name == null) {
- boolean accepted = false;
- while (!accepted) {
-
- // Try another name
- synchronized (this) {
- name = String.valueOf(nextWindowId);
- nextWindowId++;
- }
-
- if (!windows.containsKey(name)) {
- accepted = true;
- }
- }
- window.setName(name);
- }
-
- // Adds the window to application
- windows.put(name, window);
- window.setApplication(this);
-
- fireWindowAttachEvent(window);
-
- // If no main window is set, declare the window to be main window
- if (getMainWindow() == null) {
- mainWindow = window;
- }
- }
-
- /**
- * Send information to all listeners about new Windows associated with this
- * application.
- *
- * @param window
- */
- private void fireWindowAttachEvent(Window window) {
- // Fires the window attach event
- if (windowAttachListeners != null) {
- final Object[] listeners = windowAttachListeners.toArray();
- final WindowAttachEvent event = new WindowAttachEvent(window);
- for (int i = 0; i < listeners.length; i++) {
- ((WindowAttachListener) listeners[i]).windowAttached(event);
- }
- }
- }
+ private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>();
/**
- * Removes the specified window from the application.
- *
+ * Keeps track of which roots have been inited.
* <p>
- * Removing the main window of the Application also sets the main window to
- * null. One must another window to be the main window after this with
- * {@link #setMainWindow(Window)}.
+ * TODO Investigate whether this might be derived from the different states
+ * in getRootForRrequest.
* </p>
- *
- * <p>
- * Note that removing window from the application does not close the browser
- * window - the window is only removed from the server-side.
- * </p>
- *
- * @param window
- * the window to be removed.
*/
- public void removeWindow(Window window) {
- if (window != null && windows.contains(window)) {
-
- // Removes the window from application
- windows.remove(window.getName());
-
- // If the window was main window, clear it
- if (getMainWindow() == window) {
- setMainWindow(null);
- }
-
- // Removes the application from window
- if (window.getApplication() == this) {
- window.setApplication(null);
- }
-
- fireWindowDetachEvent(window);
- }
- }
-
- private void fireWindowDetachEvent(Window window) {
- // Fires the window detach event
- if (windowDetachListeners != null) {
- final Object[] listeners = windowDetachListeners.toArray();
- final WindowDetachEvent event = new WindowDetachEvent(window);
- for (int i = 0; i < listeners.length; i++) {
- ((WindowDetachListener) listeners[i]).windowDetached(event);
- }
- }
- }
+ private Set<Integer> initedRoots = new HashSet<Integer>();
/**
* Gets the user of the application.
@@ -532,11 +525,13 @@ public abstract class Application implements URIHandler,
* configuration.
* @param context
* the context application will be running in.
+ * @param productionMode
*
*/
public void start(URL applicationUrl, Properties applicationProperties,
- ApplicationContext context) {
+ ApplicationContext context, boolean productionMode) {
this.applicationUrl = applicationUrl;
+ this.productionMode = productionMode;
properties = applicationProperties;
this.context = context;
init();
@@ -560,106 +555,14 @@ public abstract class Application implements URIHandler,
}
/**
- * Gets the set of windows contained by the application.
- *
- * <p>
- * Note that the returned set of windows can not be modified.
- * </p>
- *
- * @return the Unmodifiable collection of windows.
- */
- public Collection<Window> getWindows() {
- return Collections.unmodifiableCollection(windows.values());
- }
-
- /**
* <p>
* Main initializer of the application. The <code>init</code> method is
* called by the framework when the application is started, and it should
- * perform whatever initialization operations the application needs, such as
- * creating windows and adding components to them.
- * </p>
- */
- public abstract void init();
-
- /**
- * Gets the application's theme. The application's theme is the default
- * theme used by all the windows in it that do not explicitly specify a
- * theme. If the application theme is not explicitly set, the
- * <code>null</code> is returned.
- *
- * @return the name of the application's theme.
- */
- public String getTheme() {
- return theme;
- }
-
- /**
- * Sets the application's theme.
- * <p>
- * Note that this theme can be overridden in the the application level
- * windows with {@link com.vaadin.ui.Window#setTheme(String)}. Setting theme
- * to be <code>null</code> selects the default theme. For the available
- * theme names, see the contents of the VAADIN/themes directory.
- * </p>
- *
- * @param theme
- * the new theme for this application.
- */
- public void setTheme(String theme) {
- // Collect list of windows not having the current or future theme
- final LinkedList<Window> toBeUpdated = new LinkedList<Window>();
- final String oldAppTheme = getTheme();
- for (final Iterator<Window> i = getWindows().iterator(); i.hasNext();) {
- final Window w = i.next();
- final String windowTheme = w.getTheme();
- if ((windowTheme == null)
- || (!windowTheme.equals(theme) && windowTheme
- .equals(oldAppTheme))) {
- toBeUpdated.add(w);
- }
- }
-
- // Updates the theme
- this.theme = theme;
-
- // Ask windows to update themselves
- for (final Iterator<Window> i = toBeUpdated.iterator(); i.hasNext();) {
- i.next().requestRepaint();
- }
- }
-
- /**
- * Gets the mainWindow of the application.
- *
- * <p>
- * The main window is the window attached to the application URL (
- * {@link #getURL()}) and thus which is show by default to the user.
- * </p>
- * <p>
- * Note that each application must have at least one main window.
- * </p>
- *
- * @return the main window.
- */
- public Window getMainWindow() {
- return mainWindow;
- }
-
- /**
- * <p>
- * Sets the mainWindow. If the main window is not explicitly set, the main
- * window defaults to first created window. Setting window as a main window
- * of this application also adds the window to this application.
+ * perform whatever initialization operations the application needs.
* </p>
- *
- * @param mainWindow
- * the mainWindow to set.
*/
- public void setMainWindow(Window mainWindow) {
-
- addWindow(mainWindow);
- this.mainWindow = mainWindow;
+ public void init() {
+ // Default implementation does nothing
}
/**
@@ -759,50 +662,6 @@ public abstract class Application implements URIHandler,
}
/**
- * Application URI handling hub.
- *
- * <p>
- * This method gets called by terminal. It has lots of duties like to pass
- * uri handler to proper uri handlers registered to windows etc.
- * </p>
- *
- * <p>
- * In most situations developers should NOT OVERRIDE this method. Instead
- * developers should implement and register uri handlers to windows.
- * </p>
- *
- * @deprecated this method is called be the terminal implementation only and
- * might be removed or moved in the future. Instead of
- * overriding this method, add your {@link URIHandler} to a top
- * level {@link Window} (eg.
- * getMainWindow().addUriHanler(handler) instead.
- */
- @Deprecated
- public DownloadStream handleURI(URL context, String relativeUri) {
-
- if (this.context.isApplicationResourceURL(context, relativeUri)) {
-
- // Handles the resource request
- final String key = this.context.getURLKey(context, relativeUri);
- final ApplicationResource resource = keyResourceMap.get(key);
- if (resource != null) {
- DownloadStream stream = resource.getStream();
- if (stream != null) {
- stream.setCacheTime(resource.getCacheTime());
- return stream;
- } else {
- return null;
- }
- } else {
- // Resource requests override uri handling
- return null;
- }
- } else {
- return null;
- }
- }
-
- /**
* Gets the default locale for this application.
*
* By default this is the preferred locale of the user using the
@@ -1061,68 +920,6 @@ public abstract class Application implements URIHandler,
}
/**
- * Adds the window attach listener.
- *
- * Use this to get notifications each time a window is attached to the
- * application with {@link #addWindow(Window)}.
- *
- * @param listener
- * the window attach listener to add.
- */
- public void addListener(WindowAttachListener listener) {
- if (windowAttachListeners == null) {
- windowAttachListeners = new LinkedList<WindowAttachListener>();
- }
- windowAttachListeners.add(listener);
- }
-
- /**
- * Adds the window detach listener.
- *
- * Use this to get notifications each time a window is remove from the
- * application with {@link #removeWindow(Window)}.
- *
- * @param listener
- * the window detach listener to add.
- */
- public void addListener(WindowDetachListener listener) {
- if (windowDetachListeners == null) {
- windowDetachListeners = new LinkedList<WindowDetachListener>();
- }
- windowDetachListeners.add(listener);
- }
-
- /**
- * Removes the window attach listener.
- *
- * @param listener
- * the window attach listener to remove.
- */
- public void removeListener(WindowAttachListener listener) {
- if (windowAttachListeners != null) {
- windowAttachListeners.remove(listener);
- if (windowAttachListeners.isEmpty()) {
- windowAttachListeners = null;
- }
- }
- }
-
- /**
- * Removes the window detach listener.
- *
- * @param listener
- * the window detach listener to remove.
- */
- public void removeListener(WindowDetachListener listener) {
- if (windowDetachListeners != null) {
- windowDetachListeners.remove(listener);
- if (windowDetachListeners.isEmpty()) {
- windowDetachListeners = null;
- }
- }
- }
-
- /**
* Returns the URL user is redirected to on application close. If the URL is
* <code>null</code>, the application is closed normally as defined by the
* application running environment.
@@ -1200,10 +997,6 @@ public abstract class Application implements URIHandler,
Object owner = null;
if (event instanceof VariableOwner.ErrorEvent) {
owner = ((VariableOwner.ErrorEvent) event).getVariableOwner();
- } else if (event instanceof URIHandler.ErrorEvent) {
- owner = ((URIHandler.ErrorEvent) event).getURIHandler();
- } else if (event instanceof ParameterHandler.ErrorEvent) {
- owner = ((ParameterHandler.ErrorEvent) event).getParameterHandler();
} else if (event instanceof ChangeVariablesErrorEvent) {
owner = ((ChangeVariablesErrorEvent) event).getComponent();
}
@@ -1280,6 +1073,43 @@ public abstract class Application implements URIHandler,
}
/**
+ * Gets the {@link ConverterFactory} used to locate a suitable
+ * {@link Converter} for fields in the application.
+ *
+ * See {@link #setConverterFactory(ConverterFactory)} for more details
+ *
+ * @return The converter factory used in the application
+ */
+ public ConverterFactory getConverterFactory() {
+ return converterFactory;
+ }
+
+ /**
+ * Sets the {@link ConverterFactory} used to locate a suitable
+ * {@link Converter} for fields in the application.
+ * <p>
+ * The {@link ConverterFactory} is used to find a suitable converter when
+ * binding data to a UI component and the data type does not match the UI
+ * component type, e.g. binding a Double to a TextField (which is based on a
+ * String).
+ * </p>
+ * <p>
+ * The {@link Converter} for an individual field can be overridden using
+ * {@link AbstractField#setConverter(Converter)} and for individual property
+ * ids in a {@link Table} using
+ * {@link Table#setConverter(Object, Converter)}.
+ * </p>
+ * <p>
+ * The converter factory must never be set to null.
+ *
+ * @param converterFactory
+ * The converter factory used in the application
+ */
+ public void setConverterFactory(ConverterFactory converterFactory) {
+ this.converterFactory = converterFactory;
+ }
+
+ /**
* Contains the system messages used to notify the user about various
* critical situations that can occur.
* <p>
@@ -1906,4 +1736,534 @@ public abstract class Application implements URIHandler,
}
}
-} \ No newline at end of file
+
+ /**
+ * Gets a root for a request for which no root is already known. This method
+ * is called when the framework processes a request that does not originate
+ * from an existing root instance. This typically happens when a host page
+ * is requested.
+ *
+ * <p>
+ * Subclasses of Application may override this method to provide custom
+ * logic for choosing how to create a suitable root or for picking an
+ * already created root. If an existing root is picked, care should be taken
+ * to avoid keeping the same root open in multiple browser windows, as that
+ * will cause the states to go out of sync.
+ * </p>
+ *
+ * <p>
+ * If {@link BrowserDetails} are required to create a Root, the
+ * implementation can throw a {@link RootRequiresMoreInformationException}
+ * exception. In this case, the framework will instruct the browser to send
+ * the additional details, whereupon this method is invoked again with the
+ * browser details present in the wrapped request. Throwing the exception if
+ * the browser details are already available is not supported.
+ * </p>
+ *
+ * <p>
+ * The default implementation in {@link Application} creates a new instance
+ * of the Root class returned by {@link #getRootClassName(WrappedRequest},
+ * which in turn uses the {@value #ROOT_PARAMETER} parameter from web.xml.
+ * </p>
+ *
+ * @param request
+ * the wrapped request for which a root is needed
+ * @return a root instance to use for the request
+ * @throws RootRequiresMoreInformationException
+ * may be thrown by an implementation to indicate that
+ * {@link BrowserDetails} are required to create a root
+ *
+ * @see #getRootClassName(WrappedRequest)
+ * @see Root
+ * @see RootRequiresMoreInformationException
+ * @see WrappedRequest#getBrowserDetails()
+ *
+ * @since 7.0
+ */
+ protected Root getRoot(WrappedRequest request)
+ throws RootRequiresMoreInformationException {
+ String rootClassName = getRootClassName(request);
+ try {
+ Class<? extends Root> rootClass = Class.forName(rootClassName)
+ .asSubclass(Root.class);
+ try {
+ Root root = rootClass.newInstance();
+ return root;
+ } catch (Exception e) {
+ throw new RuntimeException("Could not instantiate root class "
+ + rootClassName, e);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Could not load root class "
+ + rootClassName, e);
+ }
+ }
+
+ /**
+ * Provides the name of the <code>Root</code> class that should be used for
+ * a request. The class must have an accessible no-args constructor.
+ * <p>
+ * The default implementation uses the {@value #ROOT_PARAMETER} parameter
+ * from web.xml.
+ * </p>
+ * <p>
+ * This method is mainly used by the default implementation of
+ * {@link #getRoot(WrappedRequest)}. If you override that method with your
+ * own functionality, the results of this method might not be used.
+ * </p>
+ *
+ * @param request
+ * the request for which a new root is required
+ * @return the name of the root class to use
+ *
+ * @since 7.0
+ */
+ protected String getRootClassName(WrappedRequest request) {
+ Object rootClassNameObj = properties.get(ROOT_PARAMETER);
+ if (rootClassNameObj instanceof String) {
+ return (String) rootClassNameObj;
+ } else {
+ throw new RuntimeException("No " + ROOT_PARAMETER
+ + " defined in web.xml");
+ }
+ }
+
+ /**
+ * Finds the theme to use for a specific root. If no specific theme is
+ * required, <code>null</code> is returned.
+ *
+ * TODO Tell what the default implementation does once it does something.
+ *
+ * @param root
+ * the root to get a theme for
+ * @return the name of the theme, or <code>null</code> if the default theme
+ * should be used
+ *
+ * @since 7.0
+ */
+ public String getThemeForRoot(Root root) {
+ Theme rootTheme = getAnnotationFor(root.getClass(), Theme.class);
+ if (rootTheme != null) {
+ return rootTheme.value();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Finds the widgetset to use for a specific root. If no specific widgetset
+ * is required, <code>null</code> is returned.
+ *
+ * TODO Tell what the default implementation does once it does something.
+ *
+ * @param root
+ * the root to get a widgetset for
+ * @return the name of the widgetset, or <code>null</code> if the default
+ * widgetset should be used
+ *
+ * @since 7.0
+ */
+ public String getWidgetsetForRoot(Root root) {
+ Widgetset rootWidgetset = getAnnotationFor(root.getClass(),
+ Widgetset.class);
+ if (rootWidgetset != null) {
+ return rootWidgetset.value();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Helper to get an annotation for a class. If the annotation is not present
+ * on the target class, it's superclasses and implemented interfaces are
+ * also searched for the annotation.
+ *
+ * @param type
+ * the target class from which the annotation should be found
+ * @param annotationType
+ * the annotation type to look for
+ * @return an annotation of the given type, or <code>null</code> if the
+ * annotation is not present on the class
+ */
+ private static <T extends Annotation> T getAnnotationFor(Class<?> type,
+ Class<T> annotationType) {
+ // Find from the class hierarchy
+ Class<?> currentType = type;
+ while (currentType != Object.class) {
+ T annotation = currentType.getAnnotation(annotationType);
+ if (annotation != null) {
+ return annotation;
+ } else {
+ currentType = currentType.getSuperclass();
+ }
+ }
+
+ // Find from an implemented interface
+ for (Class<?> iface : type.getInterfaces()) {
+ T annotation = iface.getAnnotation(annotationType);
+ if (annotation != null) {
+ return annotation;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Handles a request by passing it to each registered {@link RequestHandler}
+ * in turn until one produces a response. This method is used for requests
+ * that have not been handled by any specific functionality in the terminal
+ * implementation (e.g. {@link AbstractApplicationServlet}).
+ * <p>
+ * The request handlers are invoked in the revere order in which they were
+ * added to the application until a response has been produced. This means
+ * that the most recently added handler is used first and the first request
+ * handler that was added to the application is invoked towards the end
+ * unless any previous handler has already produced a response.
+ * </p>
+ *
+ * @param request
+ * the wrapped request to get information from
+ * @param response
+ * the response to which data can be written
+ * @return returns <code>true</code> if a {@link RequestHandler} has
+ * produced a response and <code>false</code> if no response has
+ * been written.
+ * @throws IOException
+ *
+ * @see #addRequestHandler(RequestHandler)
+ * @see RequestHandler
+ *
+ * @since 7.0
+ */
+ public boolean handleRequest(WrappedRequest request,
+ WrappedResponse response) throws IOException {
+ // Use a copy to avoid ConcurrentModificationException
+ for (RequestHandler handler : new ArrayList<RequestHandler>(
+ requestHandlers)) {
+ if (handler.handleRequest(this, request, response)) {
+ return true;
+ }
+ }
+ // If not handled
+ return false;
+ }
+
+ /**
+ * Adds a request handler to this application. Request handlers can be added
+ * to provide responses to requests that are not handled by the default
+ * functionality of the framework.
+ * <p>
+ * Handlers are called in reverse order of addition, so the most recently
+ * added handler will be called first.
+ * </p>
+ *
+ * @param handler
+ * the request handler to add
+ *
+ * @see #handleRequest(WrappedRequest, WrappedResponse)
+ * @see #removeRequestHandler(RequestHandler)
+ *
+ * @since 7.0
+ */
+ public void addRequestHandler(RequestHandler handler) {
+ requestHandlers.addFirst(handler);
+ }
+
+ /**
+ * Removes a request handler from the application.
+ *
+ * @param handler
+ * the request handler to remove
+ *
+ * @since 7.0
+ */
+ public void removeRequestHandler(RequestHandler handler) {
+ requestHandlers.remove(handler);
+ }
+
+ /**
+ * Gets the request handlers that are registered to the application. The
+ * iteration order of the returned collection is the same as the order in
+ * which the request handlers will be invoked when a request is handled.
+ *
+ * @return a collection of request handlers, with the iteration order
+ * according to the order they would be invoked
+ *
+ * @see #handleRequest(WrappedRequest, WrappedResponse)
+ * @see #addRequestHandler(RequestHandler)
+ * @see #removeRequestHandler(RequestHandler)
+ *
+ * @since 7.0
+ */
+ public Collection<RequestHandler> getRequestHandlers() {
+ return Collections.unmodifiableCollection(requestHandlers);
+ }
+
+ /**
+ * Find an application resource with a given key.
+ *
+ * @param key
+ * The key of the resource
+ * @return The application resource corresponding to the provided key, or
+ * <code>null</code> if no resource is registered for the key
+ *
+ * @since 7.0
+ */
+ public ApplicationResource getResource(String key) {
+ return keyResourceMap.get(key);
+ }
+
+ /**
+ * Thread local for keeping track of currently used application instance
+ *
+ * @since 7.0
+ */
+ private static final ThreadLocal<Application> currentApplication = new ThreadLocal<Application>();
+
+ private boolean rootPreserved = false;
+
+ /**
+ * Gets the currently used application. The current application is
+ * automatically defined when processing requests to the server. In other
+ * cases, (e.g. from background threads), the current application is not
+ * automatically defined.
+ *
+ * @return the current application instance if available, otherwise
+ * <code>null</code>
+ *
+ * @see #setCurrentApplication(Application)
+ *
+ * @since 7.0
+ */
+ public static Application getCurrentApplication() {
+ return currentApplication.get();
+ }
+
+ /**
+ * Sets the thread local for the current application. This method is used by
+ * the framework to set the current application whenever a new request is
+ * processed and it is cleared when the request has been processed.
+ * <p>
+ * The application developer can also use this method to define the current
+ * application outside the normal request handling, e.g. when initiating
+ * custom background threads.
+ * </p>
+ *
+ * @param application
+ *
+ * @see #getCurrentApplication()
+ * @see ThreadLocal
+ *
+ * @since 7.0
+ */
+ public static void setCurrentApplication(Application application) {
+ currentApplication.set(application);
+ }
+
+ /**
+ * Check whether this application is in production mode. If an application
+ * is in production mode, certain debugging facilities are not available.
+ *
+ * @return the status of the production mode flag
+ *
+ * @since 7.0
+ */
+ public boolean isProductionMode() {
+ return productionMode;
+ }
+
+ /**
+ * Finds the {@link Root} to which a particular request belongs. If the
+ * request originates from an existing Root, that root is returned. In other
+ * cases, the method attempts to create and initialize a new root and might
+ * throw a {@link RootRequiresMoreInformationException} if all required
+ * information is not available.
+ * <p>
+ * Please note that this method can also return a newly created
+ * <code>Root</code> which has not yet been initialized. You can use
+ * {@link #isRootInitPending(int)} with the root's id (
+ * {@link Root#getRootId()} to check whether the initialization is still
+ * pending.
+ * </p>
+ *
+ * @param request
+ * the request for which a root is desired
+ * @return a root belonging to the request
+ * @throws RootRequiresMoreInformationException
+ * if no existing root could be found and creating a new root
+ * requires additional information from the browser
+ *
+ * @see #getRoot(WrappedRequest)
+ * @see RootRequiresMoreInformationException
+ *
+ * @since 7.0
+ */
+ public Root getRootForRequest(WrappedRequest request)
+ throws RootRequiresMoreInformationException {
+ Root root = Root.getCurrentRoot();
+ if (root != null) {
+ return root;
+ }
+ Integer rootId = getRootId(request);
+
+ synchronized (this) {
+ BrowserDetails browserDetails = request.getBrowserDetails();
+ boolean hasBrowserDetails = browserDetails != null
+ && browserDetails.getUriFragment() != null;
+
+ root = roots.get(rootId);
+
+ if (root == null && isRootPreserved()) {
+ // Check for a known root
+ if (!retainOnRefreshRoots.isEmpty()) {
+
+ Integer retainedRootId;
+ if (!hasBrowserDetails) {
+ throw new RootRequiresMoreInformationException();
+ } else {
+ String windowName = browserDetails.getWindowName();
+ retainedRootId = retainOnRefreshRoots.get(windowName);
+ }
+
+ if (retainedRootId != null) {
+ rootId = retainedRootId;
+ root = roots.get(rootId);
+ }
+ }
+ }
+
+ if (root == null) {
+ // Throws exception if root can not yet be created
+ root = getRoot(request);
+
+ // Initialize some fields for a newly created root
+ if (root.getApplication() == null) {
+ root.setApplication(this);
+ }
+ if (root.getRootId() < 0) {
+
+ if (rootId == null) {
+ // Get the next id if none defined
+ rootId = Integer.valueOf(nextRootId++);
+ }
+ root.setRootId(rootId.intValue());
+ roots.put(rootId, root);
+ }
+ }
+
+ if (!initedRoots.contains(rootId)) {
+ boolean initRequiresBrowserDetails = isRootPreserved()
+ || !root.getClass()
+ .isAnnotationPresent(EagerInit.class);
+ if (!initRequiresBrowserDetails || hasBrowserDetails) {
+ root.doInit(request);
+
+ // Remember that this root has been initialized
+ initedRoots.add(rootId);
+
+ // init() might turn on preserve so do this afterwards
+ if (isRootPreserved()) {
+ // Remember this root
+ String windowName = request.getBrowserDetails()
+ .getWindowName();
+ retainOnRefreshRoots.put(windowName, rootId);
+ }
+ }
+ }
+ } // end synchronized block
+
+ Root.setCurrentRoot(root);
+ return root;
+ }
+
+ /**
+ * Internal helper to finds the root id for a request.
+ *
+ * @param request
+ * the request to get the root id for
+ * @return a root id, or <code>null</code> if no root id is defined
+ *
+ * @since 7.0
+ */
+ private static Integer getRootId(WrappedRequest request) {
+ if (request instanceof CombinedRequest) {
+ // Combined requests has the rootid parameter in the second request
+ CombinedRequest combinedRequest = (CombinedRequest) request;
+ request = combinedRequest.getSecondRequest();
+ }
+ String rootIdString = request
+ .getParameter(ApplicationConnection.ROOT_ID_PARAMETER);
+ Integer rootId = rootIdString == null ? null
+ : new Integer(rootIdString);
+ return rootId;
+ }
+
+ /**
+ * Sets whether the same Root state should be reused if the framework can
+ * detect that the application is opened in a browser window where it has
+ * previously been open. The framework attempts to discover this by checking
+ * the value of window.name in the browser.
+ * <p>
+ * NOTE that you should avoid turning this feature on/off on-the-fly when
+ * the UI is already shown, as it might not be retained as intended.
+ * </p>
+ *
+ * @param rootPreserved
+ * <code>true</code>if the same Root instance should be reused
+ * e.g. when the browser window is refreshed.
+ */
+ public void setRootPreserved(boolean rootPreserved) {
+ this.rootPreserved = rootPreserved;
+ if (!rootPreserved) {
+ retainOnRefreshRoots.clear();
+ }
+ }
+
+ /**
+ * Checks whether the same Root state should be reused if the framework can
+ * detect that the application is opened in a browser window where it has
+ * previously been open. The framework attempts to discover this by checking
+ * the value of window.name in the browser.
+ *
+ * @return <code>true</code>if the same Root instance should be reused e.g.
+ * when the browser window is refreshed.
+ */
+ public boolean isRootPreserved() {
+ return rootPreserved;
+ }
+
+ /**
+ * Checks whether there's a pending initialization for the root with the
+ * given id.
+ *
+ * @param rootId
+ * root id to check for
+ * @return <code>true</code> of the initialization is pending,
+ * <code>false</code> if the root id is not registered or if the
+ * root has already been initialized
+ *
+ * @see #getRootForRequest(WrappedRequest)
+ */
+ public boolean isRootInitPending(int rootId) {
+ return !initedRoots.contains(Integer.valueOf(rootId));
+ }
+
+ /**
+ * Gets all the roots of this application. This includes roots that have
+ * been requested but not yet initialized. Please note, that roots are not
+ * automatically removed e.g. if the browser window is closed and that there
+ * is no way to manually remove a root. Inactive roots will thus not be
+ * released for GC until the entire application is released when the session
+ * has timed out (unless there are dangling references). Improved support
+ * for releasing unused roots is planned for an upcoming alpha release of
+ * Vaadin 7.
+ *
+ * @return a collection of roots belonging to this application
+ *
+ * @since 7.0
+ */
+ public Collection<Root> getRoots() {
+ return Collections.unmodifiableCollection(roots.values());
+ }
+}
diff --git a/src/com/vaadin/RootRequiresMoreInformationException.java b/src/com/vaadin/RootRequiresMoreInformationException.java
new file mode 100644
index 0000000000..ed0fa41437
--- /dev/null
+++ b/src/com/vaadin/RootRequiresMoreInformationException.java
@@ -0,0 +1,25 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin;
+
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedRequest.BrowserDetails;
+
+/**
+ * Exception that is thrown to indicate that creating or initializing the root
+ * requires information detailed from the web browser ({@link BrowserDetails})
+ * to be present.
+ *
+ * This exception may not be thrown if that information is already present in
+ * the current WrappedRequest.
+ *
+ * @see Application#getRoot(WrappedRequest)
+ * @see WrappedRequest#getBrowserDetails()
+ *
+ * @since 7.0
+ */
+public class RootRequiresMoreInformationException extends Exception {
+ // Nothing of interest here
+}
diff --git a/src/com/vaadin/annotations/EagerInit.java b/src/com/vaadin/annotations/EagerInit.java
new file mode 100644
index 0000000000..c7c2702d2a
--- /dev/null
+++ b/src/com/vaadin/annotations/EagerInit.java
@@ -0,0 +1,30 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.ui.Root;
+
+/**
+ * Indicates that the init method in a Root class can be called before full
+ * browser details ({@link WrappedRequest#getBrowserDetails()}) are available.
+ * This will make the UI appear more quickly, as ensuring the availability of
+ * this information typically requires an additional round trip to the client.
+ *
+ * @see Root#init(com.vaadin.terminal.WrappedRequest)
+ * @see WrappedRequest#getBrowserDetails()
+ *
+ * @since 7.0
+ *
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EagerInit {
+ // No values
+}
diff --git a/src/com/vaadin/annotations/Theme.java b/src/com/vaadin/annotations/Theme.java
new file mode 100644
index 0000000000..7c62b07741
--- /dev/null
+++ b/src/com/vaadin/annotations/Theme.java
@@ -0,0 +1,24 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.vaadin.ui.Root;
+
+/**
+ * Defines a specific theme for a {@link Root}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Theme {
+ /**
+ * @return simple name of the theme
+ */
+ public String value();
+}
diff --git a/src/com/vaadin/annotations/Widgetset.java b/src/com/vaadin/annotations/Widgetset.java
new file mode 100644
index 0000000000..99113f73f9
--- /dev/null
+++ b/src/com/vaadin/annotations/Widgetset.java
@@ -0,0 +1,25 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.vaadin.ui.Root;
+
+/**
+ * Defines a specific theme for a {@link Root}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Widgetset {
+ /**
+ * @return name of the widgetset
+ */
+ public String value();
+
+}
diff --git a/src/com/vaadin/data/Buffered.java b/src/com/vaadin/data/Buffered.java
index 28167f71df..22a4b6f9f7 100644
--- a/src/com/vaadin/data/Buffered.java
+++ b/src/com/vaadin/data/Buffered.java
@@ -77,7 +77,11 @@ public interface Buffered extends Serializable {
*
* @return <code>true</code> if the object is in write-through mode,
* <code>false</code> if it's not.
+ * @deprecated Use {@link #setBuffered(boolean)} instead. Note that
+ * setReadThrough(true), setWriteThrough(true) equals
+ * setBuffered(false)
*/
+ @Deprecated
public boolean isWriteThrough();
/**
@@ -95,7 +99,11 @@ public interface Buffered extends Serializable {
* If the implicit commit operation fails because of a
* validation error.
*
+ * @deprecated Use {@link #setBuffered(boolean)} instead. Note that
+ * setReadThrough(true), setWriteThrough(true) equals
+ * setBuffered(false)
*/
+ @Deprecated
public void setWriteThrough(boolean writeThrough) throws SourceException,
InvalidValueException;
@@ -112,7 +120,11 @@ public interface Buffered extends Serializable {
*
* @return <code>true</code> if the object is in read-through mode,
* <code>false</code> if it's not.
+ * @deprecated Use {@link #isBuffered(boolean)} instead. Note that
+ * setReadThrough(true), setWriteThrough(true) equals
+ * setBuffered(false)
*/
+ @Deprecated
public boolean isReadThrough();
/**
@@ -127,10 +139,52 @@ public interface Buffered extends Serializable {
* @throws SourceException
* If the operation fails because of an exception is thrown by
* the data source. The cause is included in the exception.
+ * @deprecated Use {@link #setBuffered(boolean)} instead. Note that
+ * setReadThrough(true), setWriteThrough(true) equals
+ * setBuffered(false)
*/
+ @Deprecated
public void setReadThrough(boolean readThrough) throws SourceException;
/**
+ * Sets the object's buffered mode to the specified status.
+ * <p>
+ * When the object is in buffered mode, an internal buffer will be used to
+ * store changes until {@link #commit()} is called. Calling
+ * {@link #discard()} will revert the internal buffer to the value of the
+ * data source.
+ * </p>
+ * <p>
+ * This is an easier way to use {@link #setReadThrough(boolean)} and
+ * {@link #setWriteThrough(boolean)} and not as error prone. Changing
+ * buffered mode will change both the read through and write through state
+ * of the object.
+ * </p>
+ * <p>
+ * Mixing calls to {@link #setBuffered(boolean)}/{@link #isBuffered()} and
+ * {@link #setReadThrough(boolean)}/{@link #isReadThrough()} or
+ * {@link #setWriteThrough(boolean)}/{@link #isWriteThrough()} is generally
+ * a bad idea.
+ * </p>
+ *
+ * @param buffered
+ * true if buffered mode should be turned on, false otherwise
+ * @since 7.0
+ */
+ public void setBuffered(boolean buffered);
+
+ /**
+ * Checks the buffered mode of this Object.
+ * <p>
+ * This method only returns true if both read and write buffering is used.
+ * </p>
+ *
+ * @return true if buffered mode is on, false otherwise
+ * @since 7.0
+ */
+ public boolean isBuffered();
+
+ /**
* Tests if the value stored in the object has been modified since it was
* last updated from the data source.
*
@@ -241,36 +295,29 @@ public interface Buffered extends Serializable {
*
* @see com.vaadin.terminal.ErrorMessage#getErrorLevel()
*/
- public int getErrorLevel() {
+ public ErrorLevel getErrorLevel() {
- int level = Integer.MIN_VALUE;
+ ErrorLevel level = null;
for (int i = 0; i < causes.length; i++) {
- final int causeLevel = (causes[i] instanceof ErrorMessage) ? ((ErrorMessage) causes[i])
- .getErrorLevel() : ErrorMessage.ERROR;
- if (causeLevel > level) {
+ final ErrorLevel causeLevel = (causes[i] instanceof ErrorMessage) ? ((ErrorMessage) causes[i])
+ .getErrorLevel() : ErrorLevel.ERROR;
+ if (level == null) {
level = causeLevel;
+ } else {
+ if (causeLevel.intValue() > level.intValue()) {
+ level = causeLevel;
+ }
}
}
- return level == Integer.MIN_VALUE ? ErrorMessage.ERROR : level;
+ return level == null ? ErrorLevel.ERROR : level;
}
/* Documented in super interface */
public void paint(PaintTarget target) throws PaintException {
target.startTag("error");
- final int level = getErrorLevel();
- if (level > 0 && level <= ErrorMessage.INFORMATION) {
- target.addAttribute("level", "info");
- } else if (level <= ErrorMessage.WARNING) {
- target.addAttribute("level", "warning");
- } else if (level <= ErrorMessage.ERROR) {
- target.addAttribute("level", "error");
- } else if (level <= ErrorMessage.CRITICAL) {
- target.addAttribute("level", "critical");
- } else {
- target.addAttribute("level", "system");
- }
+ target.addAttribute("level", getErrorLevel().getText());
// Paint all the exceptions
for (int i = 0; i < causes.length; i++) {
diff --git a/src/com/vaadin/data/Container.java b/src/com/vaadin/data/Container.java
index 7f64dc6efa..f722e07741 100644
--- a/src/com/vaadin/data/Container.java
+++ b/src/com/vaadin/data/Container.java
@@ -121,7 +121,7 @@ public interface Container extends Serializable {
* ID of the Property to retrieve
* @return Property with the given ID or <code>null</code>
*/
- public Property getContainerProperty(Object itemId, Object propertyId);
+ public Property<?> getContainerProperty(Object itemId, Object propertyId);
/**
* Gets the data type of all Properties identified by the given Property ID.
@@ -1101,4 +1101,4 @@ public interface Container extends Serializable {
*/
public void removeListener(Container.PropertySetChangeListener listener);
}
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/data/Item.java b/src/com/vaadin/data/Item.java
index 3a884a99ab..98b95aecff 100644
--- a/src/com/vaadin/data/Item.java
+++ b/src/com/vaadin/data/Item.java
@@ -30,7 +30,7 @@ public interface Item extends Serializable {
* identifier of the Property to get
* @return the Property with the given ID or <code>null</code>
*/
- public Property getItemProperty(Object id);
+ public Property<?> getItemProperty(Object id);
/**
* Gets the collection of IDs of all Properties stored in the Item.
diff --git a/src/com/vaadin/data/Property.java b/src/com/vaadin/data/Property.java
index 70d57c3aee..9fab642381 100644
--- a/src/com/vaadin/data/Property.java
+++ b/src/com/vaadin/data/Property.java
@@ -30,12 +30,15 @@ import java.io.Serializable;
* needs to be changed through the implementing class.
* </p>
*
+ * @param T
+ * type of values of the property
+ *
* @author Vaadin Ltd
* @version
* @VERSION@
* @since 3.0
*/
-public interface Property extends Serializable {
+public interface Property<T> extends Serializable {
/**
* Gets the value stored in the Property. The returned object is compatible
@@ -43,7 +46,7 @@ public interface Property extends Serializable {
*
* @return the value stored in the Property
*/
- public Object getValue();
+ public T getValue();
/**
* Sets the value of the Property.
@@ -52,37 +55,18 @@ public interface Property extends Serializable {
* missing, one should declare the Property to be in read-only mode and
* throw <code>Property.ReadOnlyException</code> in this function.
* </p>
- * Note : It is not required, but highly recommended to support setting the
- * value also as a <code>String</code> in addition to the native type of the
- * Property (as given by the <code>getType</code> method). If the
- * <code>String</code> conversion fails or is unsupported, the method should
- * throw <code>Property.ConversionException</code>. The string conversion
- * should at least understand the format returned by the
- * <code>toString</code> method of the Property.
+ *
+ * Note : Since Vaadin 7.0, setting the value of a non-String property as a
+ * String is no longer supported.
*
* @param newValue
* New value of the Property. This should be assignable to the
- * type returned by getType, but also String type should be
- * supported
+ * type returned by getType
*
* @throws Property.ReadOnlyException
* if the object is in read-only mode
- * @throws Property.ConversionException
- * if newValue can't be converted into the Property's native
- * type directly or through String
*/
- public void setValue(Object newValue) throws Property.ReadOnlyException,
- Property.ConversionException;
-
- /**
- * Returns the value of the Property in human readable textual format. The
- * return value should be assignable to the <code>setValue</code> method if
- * the Property is not in read-only mode.
- *
- * @return <code>String</code> representation of the value stored in the
- * Property
- */
- public String toString();
+ public void setValue(Object newValue) throws Property.ReadOnlyException;
/**
* Returns the type of the Property. The methods <code>getValue</code> and
@@ -93,7 +77,7 @@ public interface Property extends Serializable {
*
* @return type of the Property
*/
- public Class<?> getType();
+ public Class<? extends T> getType();
/**
* Tests if the Property is in read-only mode. In read-only mode calls to
@@ -118,90 +102,94 @@ public interface Property extends Serializable {
public void setReadOnly(boolean newStatus);
/**
- * <code>Exception</code> object that signals that a requested Property
- * modification failed because it's in read-only mode.
+ * A Property that is capable of handle a transaction that can end in commit
+ * or rollback.
*
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.0
+ * Note that this does not refer to e.g. database transactions but rather
+ * two-phase commit that allows resetting old field values on a form etc. if
+ * the commit of one of the properties fails after others have already been
+ * committed. If
+ *
+ * @param <T>
+ * The type of the property
+ * @author Vaadin Ltd
+ * @version @version@
+ * @since 7.0
*/
- @SuppressWarnings("serial")
- public class ReadOnlyException extends RuntimeException {
+ public interface Transactional<T> extends Property<T> {
/**
- * Constructs a new <code>ReadOnlyException</code> without a detail
- * message.
+ * Starts a transaction.
+ *
+ * <p>
+ * If the value is set during a transaction the value must not replace
+ * the original value until {@link #commit()} is called. Still,
+ * {@link #getValue()} must return the current value set in the
+ * transaction. Calling {@link #rollback()} while in a transaction must
+ * rollback the value to what it was before the transaction started.
+ * </p>
+ * <p>
+ * {@link ValueChangeEvent}s must not be emitted for internal value
+ * changes during a transaction. If the value changes as a result of
+ * {@link #commit()}, a {@link ValueChangeEvent} should be emitted.
+ * </p>
*/
- public ReadOnlyException() {
- }
+ public void startTransaction();
/**
- * Constructs a new <code>ReadOnlyException</code> with the specified
- * detail message.
- *
- * @param msg
- * the detail message
+ * Commits and ends the transaction that is in progress.
+ * <p>
+ * If the value is changed as a result of this operation, a
+ * {@link ValueChangeEvent} is emitted if such are supported.
+ * <p>
+ * This method has no effect if there is no transaction is in progress.
+ * <p>
+ * This method must never throw an exception.
*/
- public ReadOnlyException(String msg) {
- super(msg);
- }
+ public void commit();
+
+ /**
+ * Aborts and rolls back the transaction that is in progress.
+ * <p>
+ * The value is reset to the value before the transaction started. No
+ * {@link ValueChangeEvent} is emitted as a result of this.
+ * <p>
+ * This method has no effect if there is no transaction is in progress.
+ * <p>
+ * This method must never throw an exception.
+ */
+ public void rollback();
}
/**
- * An exception that signals that the value passed to the
- * <code>setValue</code> method couldn't be converted to the native type of
- * the Property.
+ * <code>Exception</code> object that signals that a requested Property
+ * modification failed because it's in read-only mode.
*
- * @author Vaadin Ltd
+ * @author Vaadin Ltd.
* @version
* @VERSION@
* @since 3.0
*/
@SuppressWarnings("serial")
- public class ConversionException extends RuntimeException {
+ public class ReadOnlyException extends RuntimeException {
/**
- * Constructs a new <code>ConversionException</code> without a detail
+ * Constructs a new <code>ReadOnlyException</code> without a detail
* message.
*/
- public ConversionException() {
+ public ReadOnlyException() {
}
/**
- * Constructs a new <code>ConversionException</code> with the specified
+ * Constructs a new <code>ReadOnlyException</code> with the specified
* detail message.
*
* @param msg
* the detail message
*/
- public ConversionException(String msg) {
+ public ReadOnlyException(String msg) {
super(msg);
}
-
- /**
- * Constructs a new <code>ConversionException</code> from another
- * exception.
- *
- * @param cause
- * The cause of the the conversion failure
- */
- public ConversionException(Throwable cause) {
- super(cause);
- }
-
- /**
- * Constructs a new <code>ConversionException</code> with the specified
- * detail message and cause.
- *
- * @param message
- * the detail message
- * @param cause
- * The cause of the the conversion failure
- */
- public ConversionException(String message, Throwable cause) {
- super(message, cause);
- }
}
/**
diff --git a/src/com/vaadin/data/Validator.java b/src/com/vaadin/data/Validator.java
index fc4cdf5b42..36820c1caa 100644
--- a/src/com/vaadin/data/Validator.java
+++ b/src/com/vaadin/data/Validator.java
@@ -20,15 +20,20 @@ import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;
* value.
* </p>
* <p>
- * {@link #isValid(Object)} and {@link #validate(Object)} can be used to check
- * if a value is valid. {@link #isValid(Object)} and {@link #validate(Object)}
- * must use the same validation logic so that iff {@link #isValid(Object)}
- * returns false, {@link #validate(Object)} throws an
- * {@link InvalidValueException}.
+ * {@link #validate(Object)} can be used to check if a value is valid. An
+ * {@link InvalidValueException} with an appropriate validation error message is
+ * thrown if the value is not valid.
* </p>
* <p>
* Validators must not have any side effects.
* </p>
+ * <p>
+ * Since Vaadin 7, the method isValid(Object) does not exist in the interface -
+ * {@link #validate(Object)} should be used instead, and the exception caught
+ * where applicable. Concrete classes implementing {@link Validator} can still
+ * internally implement and use isValid(Object) for convenience or to ease
+ * migration from earlier Vaadin versions.
+ * </p>
*
* @author Vaadin Ltd.
* @version
@@ -50,18 +55,6 @@ public interface Validator extends Serializable {
public void validate(Object value) throws Validator.InvalidValueException;
/**
- * Tests if the given value is valid. This method must be symmetric with
- * {@link #validate(Object)} so that {@link #validate(Object)} throws an
- * error iff this method returns false.
- *
- * @param value
- * the value to check
- * @return <code>true</code> if the value is valid, <code>false</code>
- * otherwise.
- */
- public boolean isValid(Object value);
-
- /**
* Exception that is thrown by a {@link Validator} when a value is invalid.
*
* <p>
@@ -146,8 +139,8 @@ public interface Validator extends Serializable {
*
* @see com.vaadin.terminal.ErrorMessage#getErrorLevel()
*/
- public final int getErrorLevel() {
- return ErrorMessage.ERROR;
+ public final ErrorLevel getErrorLevel() {
+ return ErrorLevel.ERROR;
}
/*
@@ -158,7 +151,7 @@ public interface Validator extends Serializable {
*/
public void paint(PaintTarget target) throws PaintException {
target.startTag("error");
- target.addAttribute("level", "error");
+ target.addAttribute("level", ErrorLevel.ERROR.getText());
// Error message
final String message = getHtmlMessage();
diff --git a/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
new file mode 100644
index 0000000000..2584a4770b
--- /dev/null
+++ b/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
@@ -0,0 +1,157 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.fieldgroup;
+
+import java.lang.reflect.Method;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.data.validator.BeanValidator;
+import com.vaadin.ui.Field;
+
+public class BeanFieldGroup<T> extends FieldGroup {
+
+ private Class<T> beanType;
+
+ private static Boolean beanValidationImplementationAvailable = null;
+
+ public BeanFieldGroup(Class<T> beanType) {
+ this.beanType = beanType;
+ }
+
+ @Override
+ protected Class<?> getPropertyType(Object propertyId) {
+ if (getItemDataSource() != null) {
+ return super.getPropertyType(propertyId);
+ } else {
+ // Data source not set so we need to figure out the type manually
+ /*
+ * toString should never really be needed as propertyId should be of
+ * form "fieldName" or "fieldName.subField[.subField2]" but the
+ * method declaration comes from parent.
+ */
+ java.lang.reflect.Field f;
+ try {
+ f = getField(beanType, propertyId.toString());
+ return f.getType();
+ } catch (SecurityException e) {
+ throw new BindException("Cannot determine type of propertyId '"
+ + propertyId + "'.", e);
+ } catch (NoSuchFieldException e) {
+ throw new BindException("Cannot determine type of propertyId '"
+ + propertyId + "'. The propertyId was not found in "
+ + beanType.getName(), e);
+ }
+ }
+ }
+
+ private static java.lang.reflect.Field getField(Class<?> cls,
+ String propertyId) throws SecurityException, NoSuchFieldException {
+ if (propertyId.contains(".")) {
+ String[] parts = propertyId.split("\\.", 2);
+ // Get the type of the field in the "cls" class
+ java.lang.reflect.Field field1 = getField(cls, parts[0]);
+ // Find the rest from the sub type
+ return getField(field1.getType(), parts[1]);
+ } else {
+ try {
+ // Try to find the field directly in the given class
+ java.lang.reflect.Field field1 = cls
+ .getDeclaredField(propertyId);
+ return field1;
+ } catch (NoSuchFieldError e) {
+ // Try super classes until we reach Object
+ Class<?> superClass = cls.getSuperclass();
+ if (superClass != Object.class) {
+ return getField(superClass, propertyId);
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method for setting the data source directly using a bean. This
+ * method wraps the bean in a {@link BeanItem} and calls
+ * {@link #setItemDataSource(Item)}.
+ *
+ * @param bean
+ * The bean to use as data source.
+ */
+ public void setItemDataSource(T bean) {
+ setItemDataSource(new BeanItem(bean));
+ }
+
+ @Override
+ public void setItemDataSource(Item item) {
+ if (!(item instanceof BeanItem)) {
+ throw new RuntimeException(getClass().getSimpleName()
+ + " only supports BeanItems as item data source");
+ }
+ super.setItemDataSource(item);
+ }
+
+ @Override
+ public BeanItem<T> getItemDataSource() {
+ return (BeanItem<T>) super.getItemDataSource();
+ }
+
+ @Override
+ public void bind(Field field, Object propertyId) {
+ if (getItemDataSource() != null) {
+ // The data source is set so the property must be found in the item.
+ // If it is not we try to add it.
+ try {
+ getItemProperty(propertyId);
+ } catch (BindException e) {
+ // Not found, try to add a nested property;
+ // BeanItem property ids are always strings so this is safe
+ getItemDataSource().addNestedProperty((String) propertyId);
+ }
+ }
+
+ super.bind(field, propertyId);
+ }
+
+ @Override
+ protected void configureField(Field<?> field) {
+ super.configureField(field);
+ // Add Bean validators if there are annotations
+ if (isBeanValidationImplementationAvailable()) {
+ BeanValidator validator = new BeanValidator(
+ beanType, getPropertyId(field).toString());
+ field.addValidator(validator);
+ if (field.getLocale() != null) {
+ validator.setLocale(field.getLocale());
+ }
+ }
+ }
+
+ /**
+ * Checks whether a bean validation implementation (e.g. Hibernate Validator
+ * or Apache Bean Validation) is available.
+ *
+ * TODO move this method to some more generic location
+ *
+ * @return true if a JSR-303 bean validation implementation is available
+ */
+ protected static boolean isBeanValidationImplementationAvailable() {
+ if (beanValidationImplementationAvailable != null) {
+ return beanValidationImplementationAvailable;
+ }
+ try {
+ Class<?> validationClass = Class
+ .forName("javax.validation.Validation");
+ Method buildFactoryMethod = validationClass
+ .getMethod("buildDefaultValidatorFactory");
+ Object factory = buildFactoryMethod.invoke(null);
+ beanValidationImplementationAvailable = (factory != null);
+ } catch (Exception e) {
+ // no bean validation implementation available
+ beanValidationImplementationAvailable = false;
+ }
+ return beanValidationImplementationAvailable;
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/data/fieldgroup/Caption.java b/src/com/vaadin/data/fieldgroup/Caption.java
new file mode 100644
index 0000000000..b990b720cd
--- /dev/null
+++ b/src/com/vaadin/data/fieldgroup/Caption.java
@@ -0,0 +1,15 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.fieldgroup;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Caption {
+ String value();
+}
diff --git a/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java b/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java
new file mode 100644
index 0000000000..569f643998
--- /dev/null
+++ b/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java
@@ -0,0 +1,156 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.fieldgroup;
+
+import java.util.EnumSet;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.fieldgroup.FieldGroup.BindException;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.AbstractTextField;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.ListSelect;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.OptionGroup;
+import com.vaadin.ui.RichTextArea;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.TextField;
+
+public class DefaultFieldGroupFieldFactory implements FieldGroupFieldFactory {
+
+ public static final Object CAPTION_PROPERTY_ID = "Caption";
+
+ public <T extends Field> T createField(Class<?> type, Class<T> fieldType) {
+ if (Enum.class.isAssignableFrom(type)) {
+ return createEnumField(type, fieldType);
+ } else if (Boolean.class.isAssignableFrom(type)
+ || boolean.class.isAssignableFrom(type)) {
+ return createBooleanField(fieldType);
+ }
+ if (AbstractTextField.class.isAssignableFrom(fieldType)) {
+ return fieldType.cast(createAbstractTextField(fieldType
+ .asSubclass(AbstractTextField.class)));
+ } else if (fieldType == RichTextArea.class) {
+ return fieldType.cast(createRichTextArea());
+ }
+ return createDefaultField(type, fieldType);
+ }
+
+ protected RichTextArea createRichTextArea() {
+ RichTextArea rta = new RichTextArea();
+ rta.setImmediate(true);
+
+ return rta;
+ }
+
+ private <T extends Field> T createEnumField(Class<?> type,
+ Class<T> fieldType) {
+ if (AbstractSelect.class.isAssignableFrom(fieldType)) {
+ AbstractSelect s = createCompatibleSelect((Class<? extends AbstractSelect>) fieldType);
+ populateWithEnumData(s, (Class<? extends Enum>) type);
+ return (T) s;
+ }
+
+ return null;
+ }
+
+ protected AbstractSelect createCompatibleSelect(
+ Class<? extends AbstractSelect> fieldType) {
+ AbstractSelect select;
+ if (fieldType.isAssignableFrom(ListSelect.class)) {
+ select = new ListSelect();
+ select.setMultiSelect(false);
+ } else if (fieldType.isAssignableFrom(NativeSelect.class)) {
+ select = new NativeSelect();
+ } else if (fieldType.isAssignableFrom(OptionGroup.class)) {
+ select = new OptionGroup();
+ select.setMultiSelect(false);
+ } else if (fieldType.isAssignableFrom(Table.class)) {
+ Table t = new Table();
+ t.setSelectable(true);
+ select = t;
+ } else {
+ select = new ComboBox(null);
+ }
+ select.setImmediate(true);
+ select.setNullSelectionAllowed(false);
+
+ return select;
+ }
+
+ protected <T extends Field> T createBooleanField(Class<T> fieldType) {
+ if (fieldType.isAssignableFrom(CheckBox.class)) {
+ CheckBox cb = new CheckBox(null);
+ cb.setImmediate(true);
+ return (T) cb;
+ } else if (AbstractTextField.class.isAssignableFrom(fieldType)) {
+ return (T) createAbstractTextField((Class<? extends AbstractTextField>) fieldType);
+ }
+
+ return null;
+ }
+
+ protected <T extends AbstractTextField> T createAbstractTextField(
+ Class<T> fieldType) {
+ if (fieldType == AbstractTextField.class) {
+ fieldType = (Class<T>) TextField.class;
+ }
+ try {
+ T field = fieldType.newInstance();
+ field.setImmediate(true);
+ return field;
+ } catch (Exception e) {
+ throw new BindException("Could not create a field of type "
+ + fieldType, e);
+ }
+ }
+
+ /**
+ * Fallback when no specific field has been created. Typically returns a
+ * TextField.
+ *
+ * @param <T>
+ * The type of field to create
+ * @param type
+ * The type of data that should be edited
+ * @param fieldType
+ * The type of field to create
+ * @return A field capable of editing the data or null if no field could be
+ * created
+ */
+ protected <T extends Field> T createDefaultField(Class<?> type,
+ Class<T> fieldType) {
+ if (fieldType.isAssignableFrom(TextField.class)) {
+ return fieldType.cast(createAbstractTextField(TextField.class));
+ }
+ return null;
+ }
+
+ /**
+ * Populates the given select with all the enums in the given {@link Enum}
+ * class. Uses {@link Enum}.toString() for caption.
+ *
+ * @param select
+ * The select to populate
+ * @param enumClass
+ * The Enum class to use
+ */
+ protected void populateWithEnumData(AbstractSelect select,
+ Class<? extends Enum> enumClass) {
+ select.removeAllItems();
+ for (Object p : select.getContainerPropertyIds()) {
+ select.removeContainerProperty(p);
+ }
+ select.addContainerProperty(CAPTION_PROPERTY_ID, String.class, "");
+ select.setItemCaptionPropertyId(CAPTION_PROPERTY_ID);
+ @SuppressWarnings("unchecked")
+ EnumSet<?> enumSet = EnumSet.allOf(enumClass);
+ for (Object r : enumSet) {
+ Item newItem = select.addItem(r);
+ newItem.getItemProperty(CAPTION_PROPERTY_ID).setValue(r.toString());
+ }
+ }
+}
diff --git a/src/com/vaadin/data/fieldgroup/FieldGroup.java b/src/com/vaadin/data/fieldgroup/FieldGroup.java
new file mode 100644
index 0000000000..3df19f5bc9
--- /dev/null
+++ b/src/com/vaadin/data/fieldgroup/FieldGroup.java
@@ -0,0 +1,978 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.fieldgroup;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.logging.Logger;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Validator.InvalidValueException;
+import com.vaadin.data.util.TransactionalPropertyWrapper;
+import com.vaadin.tools.ReflectTools;
+import com.vaadin.ui.DefaultFieldFactory;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.Form;
+
+/**
+ * FieldGroup provides an easy way of binding fields to data and handling
+ * commits of these fields.
+ * <p>
+ * The functionality of FieldGroup is similar to {@link Form} but
+ * {@link FieldGroup} does not handle layouts in any way. The typical use case
+ * is to create a layout outside the FieldGroup and then use FieldGroup to bind
+ * the fields to a data source.
+ * </p>
+ * <p>
+ * {@link FieldGroup} is not a UI component so it cannot be added to a layout.
+ * Using the buildAndBind methods {@link FieldGroup} can create fields for you
+ * using a FieldGroupFieldFactory but you still have to add them to the correct
+ * position in your layout.
+ * </p>
+ *
+ * @author Vaadin Ltd
+ * @version @version@
+ * @since 7.0
+ */
+public class FieldGroup implements Serializable {
+
+ private static final Logger logger = Logger.getLogger(FieldGroup.class
+ .getName());
+
+ private Item itemDataSource;
+ private boolean buffered = true;
+
+ private boolean enabled = true;
+ private boolean readOnly = false;
+
+ private HashMap<Object, Field<?>> propertyIdToField = new HashMap<Object, Field<?>>();
+ private LinkedHashMap<Field<?>, Object> fieldToPropertyId = new LinkedHashMap<Field<?>, Object>();
+ private List<CommitHandler> commitHandlers = new ArrayList<CommitHandler>();
+
+ /**
+ * The field factory used by builder methods.
+ */
+ private FieldGroupFieldFactory fieldFactory = new DefaultFieldGroupFieldFactory();
+
+ /**
+ * Constructs a field binder. Use {@link #setItemDataSource(Item)} to set a
+ * data source for the field binder.
+ *
+ */
+ public FieldGroup() {
+
+ }
+
+ /**
+ * Constructs a field binder that uses the given data source.
+ *
+ * @param itemDataSource
+ * The data source to bind the fields to
+ */
+ public FieldGroup(Item itemDataSource) {
+ setItemDataSource(itemDataSource);
+ }
+
+ /**
+ * Updates the item that is used by this FieldBinder. Rebinds all fields to
+ * the properties in the new item.
+ *
+ * @param itemDataSource
+ * The new item to use
+ */
+ public void setItemDataSource(Item itemDataSource) {
+ this.itemDataSource = itemDataSource;
+
+ for (Field<?> f : fieldToPropertyId.keySet()) {
+ bind(f, fieldToPropertyId.get(f));
+ }
+ }
+
+ /**
+ * Gets the item used by this FieldBinder. Note that you must call
+ * {@link #commit()} for the item to be updated unless buffered mode has
+ * been switched off.
+ *
+ * @see #setBuffered(boolean)
+ * @see #commit()
+ *
+ * @return The item used by this FieldBinder
+ */
+ public Item getItemDataSource() {
+ return itemDataSource;
+ }
+
+ /**
+ * Checks the buffered mode for the bound fields.
+ * <p>
+ *
+ * @see #setBuffered(boolean) for more details on buffered mode
+ *
+ * @see Field#isBuffered()
+ * @return true if buffered mode is on, false otherwise
+ *
+ */
+ public boolean isBuffered() {
+ return buffered;
+ }
+
+ /**
+ * Sets the buffered mode for the bound fields.
+ * <p>
+ * When buffered mode is on the item will not be updated until
+ * {@link #commit()} is called. If buffered mode is off the item will be
+ * updated once the fields are updated.
+ * </p>
+ * <p>
+ * The default is to use buffered mode.
+ * </p>
+ *
+ * @see Field#setBuffered(boolean)
+ * @param buffered
+ * true to turn on buffered mode, false otherwise
+ */
+ public void setBuffered(boolean buffered) {
+ if (buffered == this.buffered) {
+ return;
+ }
+
+ this.buffered = buffered;
+ for (Field<?> field : getFields()) {
+ field.setBuffered(buffered);
+ }
+ }
+
+ /**
+ * Returns the enabled status for the fields.
+ * <p>
+ * Note that this will not accurately represent the enabled status of all
+ * fields if you change the enabled status of the fields through some other
+ * method than {@link #setEnabled(boolean)}.
+ *
+ * @return true if the fields are enabled, false otherwise
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Updates the enabled state of all bound fields.
+ *
+ * @param fieldsEnabled
+ * true to enable all bound fields, false to disable them
+ */
+ public void setEnabled(boolean fieldsEnabled) {
+ enabled = fieldsEnabled;
+ for (Field<?> field : getFields()) {
+ field.setEnabled(fieldsEnabled);
+ }
+ }
+
+ /**
+ * Returns the read only status for the fields.
+ * <p>
+ * Note that this will not accurately represent the read only status of all
+ * fields if you change the read only status of the fields through some
+ * other method than {@link #setReadOnly(boolean)}.
+ *
+ * @return true if the fields are set to read only, false otherwise
+ */
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * Updates the read only state of all bound fields.
+ *
+ * @param fieldsReadOnly
+ * true to set all bound fields to read only, false to set them
+ * to read write
+ */
+ public void setReadOnly(boolean fieldsReadOnly) {
+ readOnly = fieldsReadOnly;
+ }
+
+ /**
+ * Returns a collection of all fields that have been bound.
+ * <p>
+ * The fields are not returned in any specific order.
+ * </p>
+ *
+ * @return A collection with all bound Fields
+ */
+ public Collection<Field<?>> getFields() {
+ return fieldToPropertyId.keySet();
+ }
+
+ /**
+ * Binds the field with the given propertyId from the current item. If an
+ * item has not been set then the binding is postponed until the item is set
+ * using {@link #setItemDataSource(Item)}.
+ * <p>
+ * This method also adds validators when applicable.
+ * </p>
+ *
+ * @param field
+ * The field to bind
+ * @param propertyId
+ * The propertyId to bind to the field
+ * @throws BindException
+ * If the property id is already bound to another field by this
+ * field binder
+ */
+ public void bind(Field<?> field, Object propertyId) throws BindException {
+ if (propertyIdToField.containsKey(propertyId)
+ && propertyIdToField.get(propertyId) != field) {
+ throw new BindException("Property id " + propertyId
+ + " is already bound to another field");
+ }
+ fieldToPropertyId.put(field, propertyId);
+ propertyIdToField.put(propertyId, field);
+ if (itemDataSource == null) {
+ // Will be bound when data source is set
+ return;
+ }
+
+ field.setPropertyDataSource(wrapInTransactionalProperty(getItemProperty(propertyId)));
+ configureField(field);
+ }
+
+ private <T> Property.Transactional<T> wrapInTransactionalProperty(
+ Property<T> itemProperty) {
+ return new TransactionalPropertyWrapper<T>(itemProperty);
+ }
+
+ /**
+ * Gets the property with the given property id from the item.
+ *
+ * @param propertyId
+ * The id if the property to find
+ * @return The property with the given id from the item
+ * @throws BindException
+ * If the property was not found in the item or no item has been
+ * set
+ */
+ protected Property<?> getItemProperty(Object propertyId)
+ throws BindException {
+ Item item = getItemDataSource();
+ if (item == null) {
+ throw new BindException("Could not lookup property with id "
+ + propertyId + " as no item has been set");
+ }
+ Property<?> p = item.getItemProperty(propertyId);
+ if (p == null) {
+ throw new BindException("A property with id " + propertyId
+ + " was not found in the item");
+ }
+ return p;
+ }
+
+ /**
+ * Detaches the field from its property id and removes it from this
+ * FieldBinder.
+ * <p>
+ * Note that the field is not detached from its property data source if it
+ * is no longer connected to the same property id it was bound to using this
+ * FieldBinder.
+ *
+ * @param field
+ * The field to detach
+ * @throws BindException
+ * If the field is not bound by this field binder or not bound
+ * to the correct property id
+ */
+ public void unbind(Field<?> field) throws BindException {
+ Object propertyId = fieldToPropertyId.get(field);
+ if (propertyId == null) {
+ throw new BindException(
+ "The given field is not part of this FieldBinder");
+ }
+
+ Property fieldDataSource = field.getPropertyDataSource();
+ if (fieldDataSource instanceof TransactionalPropertyWrapper) {
+ fieldDataSource = ((TransactionalPropertyWrapper) fieldDataSource)
+ .getWrappedProperty();
+ }
+ if (fieldDataSource == getItemProperty(propertyId)) {
+ field.setPropertyDataSource(null);
+ }
+ fieldToPropertyId.remove(field);
+ propertyIdToField.remove(propertyId);
+ }
+
+ /**
+ * Configures a field with the settings set for this FieldBinder.
+ * <p>
+ * By default this updates the buffered, read only and enabled state of the
+ * field. Also adds validators when applicable.
+ *
+ * @param field
+ * The field to update
+ */
+ protected void configureField(Field<?> field) {
+ field.setBuffered(isBuffered());
+
+ field.setEnabled(isEnabled());
+ field.setReadOnly(isReadOnly());
+ }
+
+ /**
+ * Gets the type of the property with the given property id.
+ *
+ * @param propertyId
+ * The propertyId. Must be find
+ * @return The type of the property
+ */
+ protected Class<?> getPropertyType(Object propertyId) throws BindException {
+ if (getItemDataSource() == null) {
+ throw new BindException(
+ "Property type for '"
+ + propertyId
+ + "' could not be determined. No item data source has been set.");
+ }
+ Property<?> p = getItemDataSource().getItemProperty(propertyId);
+ if (p == null) {
+ throw new BindException(
+ "Property type for '"
+ + propertyId
+ + "' could not be determined. No property with that id was found.");
+ }
+
+ return p.getType();
+ }
+
+ /**
+ * Returns a collection of all property ids that have been bound to fields.
+ * <p>
+ * Note that this will return property ids even before the item has been
+ * set. In that case it returns the property ids that will be bound once the
+ * item is set.
+ * </p>
+ * <p>
+ * No guarantee is given for the order of the property ids
+ * </p>
+ *
+ * @return A collection of bound property ids
+ */
+ public Collection<Object> getBoundPropertyIds() {
+ return Collections.unmodifiableCollection(propertyIdToField.keySet());
+ }
+
+ /**
+ * Returns a collection of all property ids that exist in the item set using
+ * {@link #setItemDataSource(Item)} but have not been bound to fields.
+ * <p>
+ * Will always return an empty collection before an item has been set using
+ * {@link #setItemDataSource(Item)}.
+ * </p>
+ * <p>
+ * No guarantee is given for the order of the property ids
+ * </p>
+ *
+ * @return A collection of property ids that have not been bound to fields
+ */
+ public Collection<Object> getUnboundPropertyIds() {
+ if (getItemDataSource() == null) {
+ return new ArrayList<Object>();
+ }
+ List<Object> unboundPropertyIds = new ArrayList<Object>();
+ unboundPropertyIds.addAll(getItemDataSource().getItemPropertyIds());
+ unboundPropertyIds.removeAll(propertyIdToField.keySet());
+ return unboundPropertyIds;
+ }
+
+ /**
+ * Commits all changes done to the bound fields.
+ * <p>
+ * Calls all {@link CommitHandler}s before and after committing the field
+ * changes to the item data source. The whole commit is aborted and state is
+ * restored to what it was before commit was called if any
+ * {@link CommitHandler} throws a CommitException or there is a problem
+ * committing the fields
+ *
+ * @throws CommitException
+ * If the commit was aborted
+ */
+ public void commit() throws CommitException {
+ if (!isBuffered()) {
+ // Not using buffered mode, nothing to do
+ return;
+ }
+ for (Field<?> f : fieldToPropertyId.keySet()) {
+ ((Property.Transactional<?>) f.getPropertyDataSource())
+ .startTransaction();
+ }
+ try {
+ firePreCommitEvent();
+ // Commit the field values to the properties
+ for (Field<?> f : fieldToPropertyId.keySet()) {
+ f.commit();
+ }
+ firePostCommitEvent();
+
+ // Commit the properties
+ for (Field<?> f : fieldToPropertyId.keySet()) {
+ ((Property.Transactional<?>) f.getPropertyDataSource())
+ .commit();
+ }
+
+ } catch (Exception e) {
+ for (Field<?> f : fieldToPropertyId.keySet()) {
+ try {
+ ((Property.Transactional<?>) f.getPropertyDataSource())
+ .rollback();
+ } catch (Exception rollbackException) {
+ // FIXME: What to do ?
+ }
+ }
+
+ throw new CommitException("Commit failed", e);
+ }
+
+ }
+
+ /**
+ * Sends a preCommit event to all registered commit handlers
+ *
+ * @throws CommitException
+ * If the commit should be aborted
+ */
+ private void firePreCommitEvent() throws CommitException {
+ CommitHandler[] handlers = commitHandlers
+ .toArray(new CommitHandler[commitHandlers.size()]);
+
+ for (CommitHandler handler : handlers) {
+ handler.preCommit(new CommitEvent(this));
+ }
+ }
+
+ /**
+ * Sends a postCommit event to all registered commit handlers
+ *
+ * @throws CommitException
+ * If the commit should be aborted
+ */
+ private void firePostCommitEvent() throws CommitException {
+ CommitHandler[] handlers = commitHandlers
+ .toArray(new CommitHandler[commitHandlers.size()]);
+
+ for (CommitHandler handler : handlers) {
+ handler.postCommit(new CommitEvent(this));
+ }
+ }
+
+ /**
+ * Discards all changes done to the bound fields.
+ * <p>
+ * Only has effect if buffered mode is used.
+ *
+ */
+ public void discard() {
+ for (Field<?> f : fieldToPropertyId.keySet()) {
+ try {
+ f.discard();
+ } catch (Exception e) {
+ // TODO: handle exception
+ // What can we do if discard fails other than try to discard all
+ // other fields?
+ }
+ }
+ }
+
+ /**
+ * Returns the field that is bound to the given property id
+ *
+ * @param propertyId
+ * The property id to use to lookup the field
+ * @return The field that is bound to the property id or null if no field is
+ * bound to that property id
+ */
+ public Field<?> getField(Object propertyId) {
+ return propertyIdToField.get(propertyId);
+ }
+
+ /**
+ * Returns the property id that is bound to the given field
+ *
+ * @param field
+ * The field to use to lookup the property id
+ * @return The property id that is bound to the field or null if the field
+ * is not bound to any property id by this FieldBinder
+ */
+ public Object getPropertyId(Field<?> field) {
+ return fieldToPropertyId.get(field);
+ }
+
+ /**
+ * Adds a commit handler.
+ * <p>
+ * The commit handler is called before the field values are committed to the
+ * item ( {@link CommitHandler#preCommit(CommitEvent)}) and after the item
+ * has been updated ({@link CommitHandler#postCommit(CommitEvent)}). If a
+ * {@link CommitHandler} throws a CommitException the whole commit is
+ * aborted and the fields retain their old values.
+ *
+ * @param commitHandler
+ * The commit handler to add
+ */
+ public void addCommitHandler(CommitHandler commitHandler) {
+ commitHandlers.add(commitHandler);
+ }
+
+ /**
+ * Removes the given commit handler.
+ *
+ * @see #addCommitHandler(CommitHandler)
+ *
+ * @param commitHandler
+ * The commit handler to remove
+ */
+ public void removeCommitHandler(CommitHandler commitHandler) {
+ commitHandlers.remove(commitHandler);
+ }
+
+ /**
+ * Returns a list of all commit handlers for this {@link FieldGroup}.
+ * <p>
+ * Use {@link #addCommitHandler(CommitHandler)} and
+ * {@link #removeCommitHandler(CommitHandler)} to register or unregister a
+ * commit handler.
+ *
+ * @return A collection of commit handlers
+ */
+ protected Collection<CommitHandler> getCommitHandlers() {
+ return Collections.unmodifiableCollection(commitHandlers);
+ }
+
+ /**
+ * CommitHandlers are used by {@link FieldGroup#commit()} as part of the
+ * commit transactions. CommitHandlers can perform custom operations as part
+ * of the commit and cause the commit to be aborted by throwing a
+ * {@link CommitException}.
+ */
+ public interface CommitHandler extends Serializable {
+ /**
+ * Called before changes are committed to the field and the item is
+ * updated.
+ * <p>
+ * Throw a {@link CommitException} to abort the commit.
+ *
+ * @param commitEvent
+ * An event containing information regarding the commit
+ * @throws CommitException
+ * if the commit should be aborted
+ */
+ public void preCommit(CommitEvent commitEvent) throws CommitException;
+
+ /**
+ * Called after changes are committed to the fields and the item is
+ * updated..
+ * <p>
+ * Throw a {@link CommitException} to abort the commit.
+ *
+ * @param commitEvent
+ * An event containing information regarding the commit
+ * @throws CommitException
+ * if the commit should be aborted
+ */
+ public void postCommit(CommitEvent commitEvent) throws CommitException;
+ }
+
+ /**
+ * FIXME javadoc
+ *
+ */
+ public static class CommitEvent implements Serializable {
+ private FieldGroup fieldBinder;
+
+ private CommitEvent(FieldGroup fieldBinder) {
+ this.fieldBinder = fieldBinder;
+ }
+
+ /**
+ * Returns the field binder that this commit relates to
+ *
+ * @return The FieldBinder that is being committed.
+ */
+ public FieldGroup getFieldBinder() {
+ return fieldBinder;
+ }
+
+ }
+
+ /**
+ * Checks the validity of the bound fields.
+ * <p>
+ * Call the {@link Field#validate()} for the fields to get the individual
+ * error messages.
+ *
+ * @return true if all bound fields are valid, false otherwise.
+ */
+ public boolean isValid() {
+ try {
+ for (Field<?> field : getFields()) {
+ field.validate();
+ }
+ return true;
+ } catch (InvalidValueException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks if any bound field has been modified.
+ *
+ * @return true if at least on field has been modified, false otherwise
+ */
+ public boolean isModified() {
+ for (Field<?> field : getFields()) {
+ if (field.isModified()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the field factory for the {@link FieldGroup}. The field factory is
+ * only used when {@link FieldGroup} creates a new field.
+ *
+ * @return The field factory in use
+ *
+ */
+ public FieldGroupFieldFactory getFieldFactory() {
+ return fieldFactory;
+ }
+
+ /**
+ * Sets the field factory for the {@link FieldGroup}. The field factory is
+ * only used when {@link FieldGroup} creates a new field.
+ *
+ * @param fieldFactory
+ * The field factory to use
+ */
+ public void setFieldFactory(FieldGroupFieldFactory fieldFactory) {
+ this.fieldFactory = fieldFactory;
+ }
+
+ /**
+ * Binds member fields found in the given object.
+ * <p>
+ * This method processes all (Java) member fields whose type extends
+ * {@link Field} and that can be mapped to a property id. Property id
+ * mapping is done based on the field name or on a @{@link PropertyId}
+ * annotation on the field. All non-null fields for which a property id can
+ * be determined are bound to the property id.
+ * </p>
+ * <p>
+ * For example:
+ *
+ * <pre>
+ * public class MyForm extends VerticalLayout {
+ * private TextField firstName = new TextField("First name");
+ * @PropertyId("last")
+ * private TextField lastName = new TextField("Last name");
+ * private TextField age = new TextField("Age"); ... }
+ *
+ * MyForm myForm = new MyForm();
+ * ...
+ * fieldGroup.bindMemberFields(myForm);
+ * </pre>
+ *
+ * </p>
+ * This binds the firstName TextField to a "firstName" property in the item,
+ * lastName TextField to a "last" property and the age TextField to a "age"
+ * property.
+ *
+ * @param objectWithMemberFields
+ * The object that contains (Java) member fields to bind
+ * @throws BindException
+ * If there is a problem binding a field
+ */
+ public void bindMemberFields(Object objectWithMemberFields)
+ throws BindException {
+ buildAndBindMemberFields(objectWithMemberFields, false);
+ }
+
+ /**
+ * Binds member fields found in the given object and builds member fields
+ * that have not been initialized.
+ * <p>
+ * This method processes all (Java) member fields whose type extends
+ * {@link Field} and that can be mapped to a property id. Property id
+ * mapping is done based on the field name or on a @{@link PropertyId}
+ * annotation on the field. Fields that are not initialized (null) are built
+ * using the field factory. All non-null fields for which a property id can
+ * be determined are bound to the property id.
+ * </p>
+ * <p>
+ * For example:
+ *
+ * <pre>
+ * public class MyForm extends VerticalLayout {
+ * private TextField firstName = new TextField("First name");
+ * @PropertyId("last")
+ * private TextField lastName = new TextField("Last name");
+ * private TextField age;
+ *
+ * MyForm myForm = new MyForm();
+ * ...
+ * fieldGroup.buildAndBindMemberFields(myForm);
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * This binds the firstName TextField to a "firstName" property in the item,
+ * lastName TextField to a "last" property and builds an age TextField using
+ * the field factory and then binds it to the "age" property.
+ * </p>
+ *
+ * @param objectWithMemberFields
+ * The object that contains (Java) member fields to build and
+ * bind
+ * @throws BindException
+ * If there is a problem binding or building a field
+ */
+ public void buildAndBindMemberFields(Object objectWithMemberFields)
+ throws BindException {
+ buildAndBindMemberFields(objectWithMemberFields, true);
+ }
+
+ /**
+ * Binds member fields found in the given object and optionally builds
+ * member fields that have not been initialized.
+ * <p>
+ * This method processes all (Java) member fields whose type extends
+ * {@link Field} and that can be mapped to a property id. Property id
+ * mapping is done based on the field name or on a @{@link PropertyId}
+ * annotation on the field. Fields that are not initialized (null) are built
+ * using the field factory is buildFields is true. All non-null fields for
+ * which a property id can be determined are bound to the property id.
+ * </p>
+ *
+ * @param objectWithMemberFields
+ * The object that contains (Java) member fields to build and
+ * bind
+ * @throws BindException
+ * If there is a problem binding or building a field
+ */
+ protected void buildAndBindMemberFields(Object objectWithMemberFields,
+ boolean buildFields) throws BindException {
+ Class<?> objectClass = objectWithMemberFields.getClass();
+
+ for (java.lang.reflect.Field memberField : objectClass
+ .getDeclaredFields()) {
+
+ if (!Field.class.isAssignableFrom(memberField.getType())) {
+ // Process next field
+ continue;
+ }
+
+ PropertyId propertyIdAnnotation = memberField
+ .getAnnotation(PropertyId.class);
+
+ Class<? extends Field> fieldType = (Class<? extends Field>) memberField
+ .getType();
+
+ Object propertyId = null;
+ if (propertyIdAnnotation != null) {
+ // @PropertyId(propertyId) always overrides property id
+ propertyId = propertyIdAnnotation.value();
+ } else {
+ propertyId = memberField.getName();
+ }
+
+ // Ensure that the property id exists
+ Class<?> propertyType;
+
+ try {
+ propertyType = getPropertyType(propertyId);
+ } catch (BindException e) {
+ // Property id was not found, skip this field
+ continue;
+ }
+
+ Field<?> field;
+ try {
+ // Get the field from the object
+ field = (Field<?>) ReflectTools.getJavaFieldValue(
+ objectWithMemberFields, memberField);
+ } catch (Exception e) {
+ // If we cannot determine the value, just skip the field and try
+ // the next one
+ continue;
+ }
+
+ if (field == null && buildFields) {
+ Caption captionAnnotation = memberField
+ .getAnnotation(Caption.class);
+ String caption;
+ if (captionAnnotation != null) {
+ caption = captionAnnotation.value();
+ } else {
+ caption = DefaultFieldFactory
+ .createCaptionByPropertyId(propertyId);
+ }
+
+ // Create the component (Field)
+ field = build(caption, propertyType, fieldType);
+
+ // Store it in the field
+ try {
+ ReflectTools.setJavaFieldValue(objectWithMemberFields,
+ memberField, field);
+ } catch (IllegalArgumentException e) {
+ throw new BindException("Could not assign value to field '"
+ + memberField.getName() + "'", e);
+ } catch (IllegalAccessException e) {
+ throw new BindException("Could not assign value to field '"
+ + memberField.getName() + "'", e);
+ } catch (InvocationTargetException e) {
+ throw new BindException("Could not assign value to field '"
+ + memberField.getName() + "'", e);
+ }
+ }
+
+ if (field != null) {
+ // Bind it to the property id
+ bind(field, propertyId);
+ }
+ }
+ }
+
+ public static class CommitException extends Exception {
+
+ public CommitException() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ public CommitException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public CommitException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public CommitException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ }
+
+ public static class BindException extends RuntimeException {
+
+ public BindException(String message) {
+ super(message);
+ }
+
+ public BindException(String message, Throwable t) {
+ super(message, t);
+ }
+
+ }
+
+ /**
+ * Builds a field and binds it to the given property id using the field
+ * binder.
+ *
+ * @param propertyId
+ * The property id to bind to. Must be present in the field
+ * finder.
+ * @throws BindException
+ * If there is a problem while building or binding
+ * @return The created and bound field
+ */
+ public Field<?> buildAndBind(Object propertyId) throws BindException {
+ String caption = DefaultFieldFactory
+ .createCaptionByPropertyId(propertyId);
+ return buildAndBind(caption, propertyId);
+ }
+
+ /**
+ * Builds a field using the given caption and binds it to the given property
+ * id using the field binder.
+ *
+ * @param caption
+ * The caption for the field
+ * @param propertyId
+ * The property id to bind to. Must be present in the field
+ * finder.
+ * @throws BindException
+ * If there is a problem while building or binding
+ * @return The created and bound field. Can be any type of {@link Field}.
+ */
+ public Field<?> buildAndBind(String caption, Object propertyId)
+ throws BindException {
+ Class<?> type = getPropertyType(propertyId);
+ return buildAndBind(caption, propertyId, Field.class);
+
+ }
+
+ /**
+ * Builds a field using the given caption and binds it to the given property
+ * id using the field binder. Ensures the new field is of the given type.
+ *
+ * @param caption
+ * The caption for the field
+ * @param propertyId
+ * The property id to bind to. Must be present in the field
+ * finder.
+ * @throws BindException
+ * If the field could not be created
+ * @return The created and bound field. Can be any type of {@link Field}.
+ */
+
+ public <T extends Field> T buildAndBind(String caption, Object propertyId,
+ Class<T> fieldType) throws BindException {
+ Class<?> type = getPropertyType(propertyId);
+
+ T field = build(caption, type, fieldType);
+ bind(field, propertyId);
+
+ return field;
+ }
+
+ /**
+ * Creates a field based on the given data type.
+ * <p>
+ * The data type is the type that we want to edit using the field. The field
+ * type is the type of field we want to create, can be {@link Field} if any
+ * Field is good.
+ * </p>
+ *
+ * @param caption
+ * The caption for the new field
+ * @param dataType
+ * The data model type that we want to edit using the field
+ * @param fieldType
+ * The type of field that we want to create
+ * @return A Field capable of editing the given type
+ * @throws BindException
+ * If the field could not be created
+ */
+ protected <T extends Field> T build(String caption, Class<?> dataType,
+ Class<T> fieldType) throws BindException {
+ T field = getFieldFactory().createField(dataType, fieldType);
+ if (field == null) {
+ throw new BindException("Unable to build a field of type "
+ + fieldType.getName() + " for editing "
+ + dataType.getName());
+ }
+
+ field.setCaption(caption);
+ return field;
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java b/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java
new file mode 100644
index 0000000000..80c012cbdc
--- /dev/null
+++ b/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java
@@ -0,0 +1,31 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.fieldgroup;
+
+import java.io.Serializable;
+
+import com.vaadin.ui.Field;
+
+/**
+ * Factory interface for creating new Field-instances based on the data type
+ * that should be edited.
+ *
+ * @author Vaadin Ltd.
+ * @version @version@
+ * @since 7.0
+ */
+public interface FieldGroupFieldFactory extends Serializable {
+ /**
+ * Creates a field based on the data type that we want to edit
+ *
+ * @param dataType
+ * The type that we want to edit using the field
+ * @param fieldType
+ * The type of field we want to create. If set to {@link Field}
+ * then any type of field is accepted
+ * @return A field that can be assigned to the given fieldType and that is
+ * capable of editing the given type of data
+ */
+ <T extends Field> T createField(Class<?> dataType, Class<T> fieldType);
+}
diff --git a/src/com/vaadin/data/fieldgroup/PropertyId.java b/src/com/vaadin/data/fieldgroup/PropertyId.java
new file mode 100644
index 0000000000..268047401d
--- /dev/null
+++ b/src/com/vaadin/data/fieldgroup/PropertyId.java
@@ -0,0 +1,15 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.fieldgroup;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PropertyId {
+ String value();
+}
diff --git a/src/com/vaadin/data/util/AbstractBeanContainer.java b/src/com/vaadin/data/util/AbstractBeanContainer.java
index 6260e05518..bed3ca0450 100644
--- a/src/com/vaadin/data/util/AbstractBeanContainer.java
+++ b/src/com/vaadin/data/util/AbstractBeanContainer.java
@@ -104,8 +104,9 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
+ " not found");
}
try {
- Property property = pd.createProperty(bean);
- return (IDTYPE) property.getValue();
+ Property<IDTYPE> property = (Property<IDTYPE>) pd
+ .createProperty(bean);
+ return property.getValue();
} catch (MethodException e) {
throw new IllegalArgumentException(e);
}
@@ -256,7 +257,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
* @see com.vaadin.data.Container#getContainerProperty(java.lang.Object,
* java.lang.Object)
*/
- public Property getContainerProperty(Object itemId, Object propertyId) {
+ public Property<?> getContainerProperty(Object itemId, Object propertyId) {
Item item = getItem(itemId);
if (item == null) {
return null;
@@ -371,7 +372,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
* The id of the property
*/
private void addValueChangeListener(Item item, Object propertyId) {
- Property property = item.getItemProperty(propertyId);
+ Property<?> property = item.getItemProperty(propertyId);
if (property instanceof ValueChangeNotifier) {
// avoid multiple notifications for the same property if
// multiple filters are in use
@@ -390,7 +391,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
* The id of the property
*/
private void removeValueChangeListener(Item item, Object propertyId) {
- Property property = item.getItemProperty(propertyId);
+ Property<?> property = item.getItemProperty(propertyId);
if (property instanceof ValueChangeNotifier) {
((ValueChangeNotifier) property).removeListener(this);
}
@@ -754,9 +755,9 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
}
model.put(propertyId, propertyDescriptor);
- for (BeanItem item : itemIdToItem.values()) {
- item.addItemProperty(propertyId, propertyDescriptor
- .createProperty((BEANTYPE) item.getBean()));
+ for (BeanItem<BEANTYPE> item : itemIdToItem.values()) {
+ item.addItemProperty(propertyId,
+ propertyDescriptor.createProperty(item.getBean()));
}
// Sends a change event
@@ -775,7 +776,6 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
* @see NestedMethodProperty
*
* @param propertyId
- * @param propertyType
* @return true if the property was added
*/
public boolean addNestedContainerProperty(String propertyId) {
@@ -783,6 +783,41 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
propertyId, type));
}
+ /**
+ * Adds a nested container properties for all sub-properties of a named
+ * property to the container. The named property itself is removed from the
+ * model as its subproperties are added.
+ *
+ * All intermediate getters must exist and must return non-null values when
+ * the property value is accessed.
+ *
+ * @see NestedMethodProperty
+ * @see #addNestedContainerProperty(String)
+ *
+ * @param propertyId
+ */
+ @SuppressWarnings("unchecked")
+ public void addNestedContainerBean(String propertyId) {
+ Class<?> propertyType = getType(propertyId);
+ LinkedHashMap<String, VaadinPropertyDescriptor<Object>> pds = BeanItem
+ .getPropertyDescriptors((Class<Object>) propertyType);
+ for (String subPropertyId : pds.keySet()) {
+ String qualifiedPropertyId = propertyId + "." + subPropertyId;
+ NestedPropertyDescriptor<BEANTYPE> pd = new NestedPropertyDescriptor<BEANTYPE>(
+ qualifiedPropertyId, (Class<BEANTYPE>) type);
+ model.put(qualifiedPropertyId, pd);
+ model.remove(propertyId);
+ for (BeanItem<BEANTYPE> item : itemIdToItem.values()) {
+ item.addItemProperty(propertyId,
+ pd.createProperty(item.getBean()));
+ item.removeItemProperty(propertyId);
+ }
+ }
+
+ // Sends a change event
+ fireContainerPropertySetChange();
+ }
+
@Override
public boolean removeContainerProperty(Object propertyId)
throws UnsupportedOperationException {
diff --git a/src/com/vaadin/data/util/AbstractProperty.java b/src/com/vaadin/data/util/AbstractProperty.java
index f9c6faacf1..3b6db3807e 100644
--- a/src/com/vaadin/data/util/AbstractProperty.java
+++ b/src/com/vaadin/data/util/AbstractProperty.java
@@ -17,7 +17,7 @@ import com.vaadin.data.Property;
*
* @since 6.6
*/
-public abstract class AbstractProperty implements Property,
+public abstract class AbstractProperty<T> implements Property<T>,
Property.ValueChangeNotifier, Property.ReadOnlyStatusChangeNotifier {
/**
@@ -56,18 +56,17 @@ public abstract class AbstractProperty implements Property,
/**
* Returns the value of the <code>Property</code> in human readable textual
- * format. The return value should be assignable to the
- * <code>setValue</code> method if the Property is not in read-only mode.
+ * format.
*
* @return String representation of the value stored in the Property
+ * @deprecated use {@link #getValue()} instead and possibly toString on that
*/
+ @Deprecated
@Override
public String toString() {
- final Object value = getValue();
- if (value == null) {
- return null;
- }
- return value.toString();
+ throw new UnsupportedOperationException(
+ "Use Property.getValue() instead of " + getClass()
+ + ".toString()");
}
/* Events */
@@ -76,8 +75,8 @@ public abstract class AbstractProperty implements Property,
* An <code>Event</code> object specifying the Property whose read-only
* status has been changed.
*/
- protected class ReadOnlyStatusChangeEvent extends java.util.EventObject
- implements Property.ReadOnlyStatusChangeEvent {
+ protected static class ReadOnlyStatusChangeEvent extends
+ java.util.EventObject implements Property.ReadOnlyStatusChangeEvent {
/**
* Constructs a new read-only status change event for this object.
@@ -144,8 +143,8 @@ public abstract class AbstractProperty implements Property,
* An <code>Event</code> object specifying the Property whose value has been
* changed.
*/
- private class ValueChangeEvent extends java.util.EventObject implements
- Property.ValueChangeEvent {
+ private static class ValueChangeEvent extends java.util.EventObject
+ implements Property.ValueChangeEvent {
/**
* Constructs a new value change event for this object.
diff --git a/src/com/vaadin/data/util/BeanItem.java b/src/com/vaadin/data/util/BeanItem.java
index ed59baa9f8..94439471f5 100644
--- a/src/com/vaadin/data/util/BeanItem.java
+++ b/src/com/vaadin/data/util/BeanItem.java
@@ -12,9 +12,11 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* A wrapper class for adding the Item interface to any Java Bean.
@@ -162,7 +164,7 @@ public class BeanItem<BT> extends PropertysetItem {
final Method getMethod = pd.getReadMethod();
if ((getMethod != null)
&& getMethod.getDeclaringClass() != Object.class) {
- VaadinPropertyDescriptor<BT> vaadinPropertyDescriptor = new MethodPropertyDescriptor(
+ VaadinPropertyDescriptor<BT> vaadinPropertyDescriptor = new MethodPropertyDescriptor<BT>(
pd.getName(), pd.getPropertyType(),
pd.getReadMethod(), pd.getWriteMethod());
pdMap.put(pd.getName(), vaadinPropertyDescriptor);
@@ -213,6 +215,49 @@ public class BeanItem<BT> extends PropertysetItem {
}
/**
+ * Expands nested bean properties by replacing a top-level property with
+ * some or all of its sub-properties. The expansion is not recursive.
+ *
+ * @param propertyId
+ * property id for the property whose sub-properties are to be
+ * expanded,
+ * @param subPropertyIds
+ * sub-properties to expand, all sub-properties are expanded if
+ * not specified
+ */
+ public void expandProperty(String propertyId, String... subPropertyIds) {
+ Set<String> subPropertySet = new HashSet<String>(
+ Arrays.asList(subPropertyIds));
+
+ if (0 == subPropertyIds.length) {
+ // Enumerate all sub-properties
+ Class<?> propertyType = getItemProperty(propertyId).getType();
+ Map<String, ?> pds = getPropertyDescriptors(propertyType);
+ subPropertySet.addAll(pds.keySet());
+ }
+
+ for (String subproperty : subPropertySet) {
+ String qualifiedPropertyId = propertyId + "." + subproperty;
+ addNestedProperty(qualifiedPropertyId);
+ }
+
+ removeItemProperty(propertyId);
+ }
+
+ /**
+ * Adds a nested property to the item.
+ *
+ * @param nestedPropertyId
+ * property id to add. This property must not exist in the item
+ * already and must of of form "field1.field2" where field2 is a
+ * field in the object referenced to by field1
+ */
+ public void addNestedProperty(String nestedPropertyId) {
+ addItemProperty(nestedPropertyId, new NestedMethodProperty<Object>(
+ getBean(), nestedPropertyId));
+ }
+
+ /**
* Gets the underlying JavaBean object.
*
* @return the bean object.
diff --git a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
index e5972f697e..91950f5d4f 100644
--- a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
+++ b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
@@ -641,7 +641,7 @@ public class ContainerHierarchicalWrapper implements Container.Hierarchical,
* Container Don't add a JavaDoc comment here, we use the default
* documentation from implemented interface.
*/
- public Property getContainerProperty(Object itemId, Object propertyId) {
+ public Property<?> getContainerProperty(Object itemId, Object propertyId) {
return container.getContainerProperty(itemId, propertyId);
}
diff --git a/src/com/vaadin/data/util/ContainerOrderedWrapper.java b/src/com/vaadin/data/util/ContainerOrderedWrapper.java
index 1600699362..f333edecf4 100644
--- a/src/com/vaadin/data/util/ContainerOrderedWrapper.java
+++ b/src/com/vaadin/data/util/ContainerOrderedWrapper.java
@@ -437,7 +437,7 @@ public class ContainerOrderedWrapper implements Container.Ordered,
* Container Don't add a JavaDoc comment here, we use the default
* documentation from implemented interface.
*/
- public Property getContainerProperty(Object itemId, Object propertyId) {
+ public Property<?> getContainerProperty(Object itemId, Object propertyId) {
return container.getContainerProperty(itemId, propertyId);
}
diff --git a/src/com/vaadin/data/util/DefaultItemSorter.java b/src/com/vaadin/data/util/DefaultItemSorter.java
index 9b834f4a2e..47db5d7507 100644
--- a/src/com/vaadin/data/util/DefaultItemSorter.java
+++ b/src/com/vaadin/data/util/DefaultItemSorter.java
@@ -122,8 +122,8 @@ public class DefaultItemSorter implements ItemSorter {
Item item1, Item item2) {
// Get the properties to compare
- final Property property1 = item1.getItemProperty(propertyId);
- final Property property2 = item2.getItemProperty(propertyId);
+ final Property<?> property1 = item1.getItemProperty(propertyId);
+ final Property<?> property2 = item2.getItemProperty(propertyId);
// Get the values to compare
final Object value1 = (property1 == null) ? null : property1.getValue();
diff --git a/src/com/vaadin/data/util/FilesystemContainer.java b/src/com/vaadin/data/util/FilesystemContainer.java
index 8e9873334b..7100286712 100644
--- a/src/com/vaadin/data/util/FilesystemContainer.java
+++ b/src/com/vaadin/data/util/FilesystemContainer.java
@@ -459,7 +459,7 @@ public class FilesystemContainer implements Container.Hierarchical {
* the property's ID.
* @return the requested property's value, or <code>null</code>
*/
- public Property getContainerProperty(Object itemId, Object propertyId) {
+ public Property<?> getContainerProperty(Object itemId, Object propertyId) {
if (!(itemId instanceof File)) {
return null;
@@ -609,7 +609,7 @@ public class FilesystemContainer implements Container.Hierarchical {
* Gets the specified property of this file. Don't add a JavaDoc comment
* here, we use the default documentation from implemented interface.
*/
- public Property getItemProperty(Object id) {
+ public Property<?> getItemProperty(Object id) {
return getContainerProperty(file, id);
}
diff --git a/src/com/vaadin/data/util/IndexedContainer.java b/src/com/vaadin/data/util/IndexedContainer.java
index 9728c79864..1e0a2fae1a 100644
--- a/src/com/vaadin/data/util/IndexedContainer.java
+++ b/src/com/vaadin/data/util/IndexedContainer.java
@@ -5,7 +5,6 @@
package com.vaadin.data.util;
import java.io.Serializable;
-import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -76,7 +75,7 @@ public class IndexedContainer extends
/**
* Set of properties that are read-only.
*/
- private HashSet<Property> readOnlyProperties = new HashSet<Property>();
+ private HashSet<Property<?>> readOnlyProperties = new HashSet<Property<?>>();
/**
* List of all Property value change event listeners listening all the
@@ -150,7 +149,7 @@ public class IndexedContainer extends
* @see com.vaadin.data.Container#getContainerProperty(java.lang.Object,
* java.lang.Object)
*/
- public Property getContainerProperty(Object itemId, Object propertyId) {
+ public Property<?> getContainerProperty(Object itemId, Object propertyId) {
if (!containsId(itemId)) {
return null;
}
@@ -425,7 +424,7 @@ public class IndexedContainer extends
* @VERSION@
* @since 3.0
*/
- public class ItemSetChangeEvent extends BaseItemSetChangeEvent {
+ public static class ItemSetChangeEvent extends BaseItemSetChangeEvent {
private final int addedItemIndex;
@@ -455,7 +454,7 @@ public class IndexedContainer extends
* @VERSION@
* @since 3.0
*/
- private class PropertyValueChangeEvent extends EventObject implements
+ private static class PropertyValueChangeEvent extends EventObject implements
Property.ValueChangeEvent, Serializable {
private PropertyValueChangeEvent(Property source) {
@@ -680,7 +679,7 @@ public class IndexedContainer extends
*
* @see com.vaadin.data.Item#getItemProperty(java.lang.Object)
*/
- public Property getItemProperty(Object id) {
+ public Property<?> getItemProperty(Object id) {
return new IndexedContainerProperty(itemId, id);
}
@@ -691,8 +690,8 @@ public class IndexedContainer extends
/**
* Gets the <code>String</code> representation of the contents of the
* Item. The format of the string is a space separated catenation of the
- * <code>String</code> representations of the Properties contained by
- * the Item.
+ * <code>String</code> representations of the values of the Properties
+ * contained by the Item.
*
* @return <code>String</code> representation of the Item contents
*/
@@ -702,7 +701,7 @@ public class IndexedContainer extends
for (final Iterator<?> i = propertyIds.iterator(); i.hasNext();) {
final Object propertyId = i.next();
- retValue += getItemProperty(propertyId).toString();
+ retValue += getItemProperty(propertyId).getValue();
if (i.hasNext()) {
retValue += " ";
}
@@ -786,7 +785,7 @@ public class IndexedContainer extends
* @VERSION@
* @since 3.0
*/
- private class IndexedContainerProperty implements Property,
+ private class IndexedContainerProperty implements Property<Object>,
Property.ValueChangeNotifier {
/**
@@ -865,8 +864,7 @@ public class IndexedContainer extends
*
* @see com.vaadin.data.Property#setValue(java.lang.Object)
*/
- public void setValue(Object newValue)
- throws Property.ReadOnlyException, Property.ConversionException {
+ public void setValue(Object newValue) throws Property.ReadOnlyException {
// Gets the Property set
final Map<Object, Object> propertySet = items.get(itemId);
@@ -877,22 +875,8 @@ public class IndexedContainer extends
} else if (getType().isAssignableFrom(newValue.getClass())) {
propertySet.put(propertyId, newValue);
} else {
- try {
-
- // Gets the string constructor
- final Constructor<?> constr = getType().getConstructor(
- new Class[] { String.class });
-
- // Creates new object from the string
- propertySet.put(propertyId, constr
- .newInstance(new Object[] { newValue.toString() }));
-
- } catch (final java.lang.Exception e) {
- throw new Property.ConversionException(
- "Conversion for value '" + newValue + "' of class "
- + newValue.getClass().getName() + " to "
- + getType().getName() + " failed", e);
- }
+ throw new IllegalArgumentException("Value is of invalid type, "
+ + getType().getName() + " expected");
}
// update the container filtering if this property is being filtered
@@ -910,14 +894,14 @@ public class IndexedContainer extends
*
* @return <code>String</code> representation of the value stored in the
* Property
+ * @deprecated use {@link #getValue()} instead and possibly toString on
+ * that
*/
+ @Deprecated
@Override
public String toString() {
- final Object value = getValue();
- if (value == null) {
- return null;
- }
- return value.toString();
+ throw new UnsupportedOperationException(
+ "Use Property.getValue() instead of IndexedContainerProperty.toString()");
}
/**
@@ -1038,7 +1022,7 @@ public class IndexedContainer extends
getPropertySetChangeListeners()) : null);
nc.propertyValueChangeListeners = propertyValueChangeListeners != null ? (LinkedList<Property.ValueChangeListener>) propertyValueChangeListeners
.clone() : null;
- nc.readOnlyProperties = readOnlyProperties != null ? (HashSet<Property>) readOnlyProperties
+ nc.readOnlyProperties = readOnlyProperties != null ? (HashSet<Property<?>>) readOnlyProperties
.clone() : null;
nc.singlePropertyValueChangeListeners = singlePropertyValueChangeListeners != null ? (Hashtable<Object, Map<Object, List<Property.ValueChangeListener>>>) singlePropertyValueChangeListeners
.clone() : null;
@@ -1097,4 +1081,4 @@ public class IndexedContainer extends
removeFilter(filter);
}
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/data/util/MethodProperty.java b/src/com/vaadin/data/util/MethodProperty.java
index ff258d3e0f..4fc5531320 100644
--- a/src/com/vaadin/data/util/MethodProperty.java
+++ b/src/com/vaadin/data/util/MethodProperty.java
@@ -5,7 +5,6 @@
package com.vaadin.data.util;
import java.io.IOException;
-import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
@@ -47,7 +46,7 @@ import com.vaadin.util.SerializerHelper;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class MethodProperty<T> extends AbstractProperty {
+public class MethodProperty<T> extends AbstractProperty<T> {
private static final Logger logger = Logger.getLogger(MethodProperty.class
.getName());
@@ -170,7 +169,7 @@ public class MethodProperty<T> extends AbstractProperty {
@SuppressWarnings("unchecked")
public MethodProperty(Object instance, String beanPropertyName) {
- final Class beanClass = instance.getClass();
+ final Class<?> beanClass = instance.getClass();
// Assure that the first letter is upper cased (it is a common
// mistake to write firstName, not FirstName).
@@ -349,7 +348,7 @@ public class MethodProperty<T> extends AbstractProperty {
}
// Tests the parameter types
- final Class[] c = m[i].getParameterTypes();
+ final Class<?>[] c = m[i].getParameterTypes();
if (c.length != getArgs.length) {
// not the right amount of parameters, try next method
@@ -398,7 +397,7 @@ public class MethodProperty<T> extends AbstractProperty {
}
// Checks parameter compatibility
- final Class[] c = m[i].getParameterTypes();
+ final Class<?>[] c = m[i].getParameterTypes();
if (c.length != setArgs.length) {
// not the right amount of parameters, try next method
@@ -474,7 +473,9 @@ public class MethodProperty<T> extends AbstractProperty {
* {@link #setValue(Object newValue)} is called.
*/
@SuppressWarnings("unchecked")
- public MethodProperty(Class type, Object instance, Method getMethod,
+ // cannot use "Class<? extends T>" because of automatic primitive type
+ // conversions
+ public MethodProperty(Class<?> type, Object instance, Method getMethod,
Method setMethod, Object[] getArgs, Object[] setArgs,
int setArgumentIndex) {
@@ -495,13 +496,13 @@ public class MethodProperty<T> extends AbstractProperty {
}
// Gets the return type from get method
- type = convertPrimitiveType(type);
+ Class<? extends T> convertedType = (Class<? extends T>) convertPrimitiveType(type);
this.getMethod = getMethod;
this.setMethod = setMethod;
setArguments(getArgs, setArgs, setArgumentIndex);
this.instance = instance;
- this.type = type;
+ this.type = convertedType;
}
/**
@@ -569,8 +570,7 @@ public class MethodProperty<T> extends AbstractProperty {
*
* @return type of the Property
*/
- @SuppressWarnings("unchecked")
- public final Class getType() {
+ public final Class<? extends T> getType() {
return type;
}
@@ -593,9 +593,9 @@ public class MethodProperty<T> extends AbstractProperty {
*
* @return the value of the Property
*/
- public Object getValue() {
+ public T getValue() {
try {
- return getMethod.invoke(instance, getArgs);
+ return (T) getMethod.invoke(instance, getArgs);
} catch (final Throwable e) {
throw new MethodException(this, e);
}
@@ -629,61 +629,33 @@ public class MethodProperty<T> extends AbstractProperty {
}
/**
- * Sets the value of the property. This method supports setting from
- * <code>String</code>s if either <code>String</code> is directly assignable
- * to property type, or the type class contains a string constructor.
+ * Sets the value of the property.
+ *
+ * Note that since Vaadin 7, no conversions are performed and the value must
+ * be of the correct type.
*
* @param newValue
* the New value of the property.
* @throws <code>Property.ReadOnlyException</code> if the object is in
* read-only mode.
- * @throws <code>Property.ConversionException</code> if
- * <code>newValue</code> can't be converted into the Property's
- * native type directly or through <code>String</code>.
* @see #invokeSetMethod(Object)
*/
@SuppressWarnings("unchecked")
- public void setValue(Object newValue) throws Property.ReadOnlyException,
- Property.ConversionException {
+ public void setValue(Object newValue) throws Property.ReadOnlyException {
// Checks the mode
if (isReadOnly()) {
throw new Property.ReadOnlyException();
}
- Object value = convertValue(newValue, type);
-
- invokeSetMethod(value);
- fireValueChange();
- }
-
- /**
- * Convert a value to the given type, using a constructor of the type that
- * takes a single String parameter (toString() for the value) if necessary.
- *
- * @param value
- * to convert
- * @param type
- * type into which the value should be converted
- * @return converted value
- */
- static Object convertValue(Object value, Class<?> type) {
- if (null == value || type.isAssignableFrom(value.getClass())) {
- return value;
+ // Checks the type of the value
+ if (newValue != null && !type.isAssignableFrom(newValue.getClass())) {
+ throw new IllegalArgumentException(
+ "Invalid value type for ObjectProperty.");
}
- // convert using a string constructor
- try {
- // Gets the string constructor
- final Constructor constr = type
- .getConstructor(new Class[] { String.class });
-
- // Create a new object from the string
- return constr.newInstance(new Object[] { value.toString() });
-
- } catch (final java.lang.Exception e) {
- throw new Property.ConversionException(e);
- }
+ invokeSetMethod((T) newValue);
+ fireValueChange();
}
/**
@@ -692,7 +664,7 @@ public class MethodProperty<T> extends AbstractProperty {
*
* @param value
*/
- protected void invokeSetMethod(Object value) {
+ protected void invokeSetMethod(T value) {
try {
// Construct a temporary argument array only if needed
diff --git a/src/com/vaadin/data/util/MethodPropertyDescriptor.java b/src/com/vaadin/data/util/MethodPropertyDescriptor.java
index f0c879766b..10faa7a0f3 100644
--- a/src/com/vaadin/data/util/MethodPropertyDescriptor.java
+++ b/src/com/vaadin/data/util/MethodPropertyDescriptor.java
@@ -123,9 +123,9 @@ public class MethodPropertyDescriptor<BT> implements
return propertyType;
}
- public Property createProperty(Object bean) {
+ public Property<?> createProperty(Object bean) {
return new MethodProperty<Object>(propertyType, bean, readMethod,
writeMethod);
}
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/data/util/NestedMethodProperty.java b/src/com/vaadin/data/util/NestedMethodProperty.java
index 8f5a17af16..d7b0f44912 100644
--- a/src/com/vaadin/data/util/NestedMethodProperty.java
+++ b/src/com/vaadin/data/util/NestedMethodProperty.java
@@ -26,7 +26,7 @@ import com.vaadin.data.util.MethodProperty.MethodException;
*
* @since 6.6
*/
-public class NestedMethodProperty extends AbstractProperty {
+public class NestedMethodProperty<T> extends AbstractProperty<T> {
// needed for de-serialization
private String propertyName;
@@ -43,7 +43,7 @@ public class NestedMethodProperty extends AbstractProperty {
*/
private Object instance;
- private Class<?> type;
+ private Class<? extends T> type;
/* Special serialization to handle method references */
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
@@ -158,13 +158,14 @@ public class NestedMethodProperty extends AbstractProperty {
} catch (final NoSuchMethodException skipped) {
}
- this.type = MethodProperty.convertPrimitiveType(type);
+ this.type = (Class<? extends T>) MethodProperty
+ .convertPrimitiveType(type);
this.propertyName = propertyName;
this.getMethods = getMethods;
this.setMethod = setMethod;
}
- public Class<?> getType() {
+ public Class<? extends T> getType() {
return type;
}
@@ -179,42 +180,41 @@ public class NestedMethodProperty extends AbstractProperty {
*
* @return the value of the Property
*/
- public Object getValue() {
+ public T getValue() {
try {
Object object = instance;
for (Method m : getMethods) {
object = m.invoke(object);
}
- return object;
+ return (T) object;
} catch (final Throwable e) {
throw new MethodException(this, e);
}
}
/**
- * Sets the value of the property. This method supports setting from
- * <code>String</code>s if either <code>String</code> is directly assignable
- * to property type, or the type class contains a string constructor.
+ * Sets the value of the property. The new value must be assignable to the
+ * type of this property.
*
* @param newValue
* the New value of the property.
* @throws <code>Property.ReadOnlyException</code> if the object is in
* read-only mode.
- * @throws <code>Property.ConversionException</code> if
- * <code>newValue</code> can't be converted into the Property's
- * native type directly or through <code>String</code>.
* @see #invokeSetMethod(Object)
*/
- public void setValue(Object newValue) throws ReadOnlyException,
- ConversionException {
+ public void setValue(Object newValue) throws ReadOnlyException {
// Checks the mode
if (isReadOnly()) {
throw new Property.ReadOnlyException();
}
- Object value = MethodProperty.convertValue(newValue, type);
+ // Checks the type of the value
+ if (newValue != null && !type.isAssignableFrom(newValue.getClass())) {
+ throw new IllegalArgumentException(
+ "Invalid value type for NestedMethodProperty.");
+ }
- invokeSetMethod(value);
+ invokeSetMethod((T) newValue);
fireValueChange();
}
@@ -224,7 +224,7 @@ public class NestedMethodProperty extends AbstractProperty {
*
* @param value
*/
- protected void invokeSetMethod(Object value) {
+ protected void invokeSetMethod(T value) {
try {
Object object = instance;
for (int i = 0; i < getMethods.size() - 1; i++) {
diff --git a/src/com/vaadin/data/util/NestedPropertyDescriptor.java b/src/com/vaadin/data/util/NestedPropertyDescriptor.java
index abdb9e0cd3..6404f6361d 100644
--- a/src/com/vaadin/data/util/NestedPropertyDescriptor.java
+++ b/src/com/vaadin/data/util/NestedPropertyDescriptor.java
@@ -37,7 +37,8 @@ public class NestedPropertyDescriptor<BT> implements
public NestedPropertyDescriptor(String name, Class<BT> beanType)
throws IllegalArgumentException {
this.name = name;
- NestedMethodProperty property = new NestedMethodProperty(beanType, name);
+ NestedMethodProperty<?> property = new NestedMethodProperty<Object>(
+ beanType, name);
this.propertyType = property.getType();
}
@@ -49,8 +50,8 @@ public class NestedPropertyDescriptor<BT> implements
return propertyType;
}
- public Property createProperty(BT bean) {
- return new NestedMethodProperty(bean, name);
+ public Property<?> createProperty(BT bean) {
+ return new NestedMethodProperty<Object>(bean, name);
}
}
diff --git a/src/com/vaadin/data/util/ObjectProperty.java b/src/com/vaadin/data/util/ObjectProperty.java
index 4319ea7716..9c60b9146e 100644
--- a/src/com/vaadin/data/util/ObjectProperty.java
+++ b/src/com/vaadin/data/util/ObjectProperty.java
@@ -4,8 +4,6 @@
package com.vaadin.data.util;
-import java.lang.reflect.Constructor;
-
import com.vaadin.data.Property;
/**
@@ -19,7 +17,7 @@ import com.vaadin.data.Property;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class ObjectProperty<T> extends AbstractProperty {
+public class ObjectProperty<T> extends AbstractProperty<T> {
/**
* The value contained by the Property.
@@ -48,9 +46,8 @@ public class ObjectProperty<T> extends AbstractProperty {
/**
* Creates a new instance of ObjectProperty with the given value and type.
*
- * Any value of type Object is accepted because, if the type class contains
- * a string constructor, the toString of the value is used to create the new
- * value. See {@link #setValue(Object)}.
+ * Since Vaadin 7, only values of the correct type are accepted, and no
+ * automatic conversions are performed.
*
* @param value
* the Initial value of the Property.
@@ -58,7 +55,7 @@ public class ObjectProperty<T> extends AbstractProperty {
* the type of the value. The value must be assignable to given
* type.
*/
- public ObjectProperty(Object value, Class<T> type) {
+ public ObjectProperty(T value, Class<T> type) {
// Set the values
this.type = type;
@@ -69,7 +66,7 @@ public class ObjectProperty<T> extends AbstractProperty {
* Creates a new instance of ObjectProperty with the given value, type and
* read-only mode status.
*
- * Any value of type Object is accepted, see
+ * Since Vaadin 7, only the correct type of values is accepted, see
* {@link #ObjectProperty(Object, Class)}.
*
* @param value
@@ -80,7 +77,7 @@ public class ObjectProperty<T> extends AbstractProperty {
* @param readOnly
* Sets the read-only mode.
*/
- public ObjectProperty(Object value, Class<T> type, boolean readOnly) {
+ public ObjectProperty(T value, Class<T> type, boolean readOnly) {
this(value, type);
setReadOnly(readOnly);
}
@@ -108,49 +105,34 @@ public class ObjectProperty<T> extends AbstractProperty {
}
/**
- * Sets the value of the property. This method supports setting from
- * <code>String</code> if either <code>String</code> is directly assignable
- * to property type, or the type class contains a string constructor.
+ * Sets the value of the property.
+ *
+ * Note that since Vaadin 7, no conversions are performed and the value must
+ * be of the correct type.
*
* @param newValue
* the New value of the property.
* @throws <code>Property.ReadOnlyException</code> if the object is in
* read-only mode
- * @throws <code>Property.ConversionException</code> if the newValue can't
- * be converted into the Property's native type directly or through
- * <code>String</code>
*/
- public void setValue(Object newValue) throws Property.ReadOnlyException,
- Property.ConversionException {
+ @SuppressWarnings("unchecked")
+ public void setValue(Object newValue) throws Property.ReadOnlyException {
// Checks the mode
if (isReadOnly()) {
throw new Property.ReadOnlyException();
}
- // Tries to assign the compatible value directly
- if (newValue == null || type.isAssignableFrom(newValue.getClass())) {
- @SuppressWarnings("unchecked")
- // the cast is safe after an isAssignableFrom check
- T value = (T) newValue;
- this.value = value;
- } else {
- try {
-
- // Gets the string constructor
- final Constructor<T> constr = getType().getConstructor(
- new Class[] { String.class });
-
- // Creates new object from the string
- value = constr
- .newInstance(new Object[] { newValue.toString() });
-
- } catch (final java.lang.Exception e) {
- throw new Property.ConversionException(e);
- }
+ // Checks the type of the value
+ if (newValue != null && !type.isAssignableFrom(newValue.getClass())) {
+ throw new IllegalArgumentException("Invalid value type "
+ + newValue.getClass().getName()
+ + " for ObjectProperty of type " + type.getName() + ".");
}
+ // the cast is safe after an isAssignableFrom check
+ this.value = (T) newValue;
+
fireValueChange();
}
-
}
diff --git a/src/com/vaadin/data/util/PropertyFormatter.java b/src/com/vaadin/data/util/PropertyFormatter.java
index 1491f9a25e..a63973535b 100644
--- a/src/com/vaadin/data/util/PropertyFormatter.java
+++ b/src/com/vaadin/data/util/PropertyFormatter.java
@@ -4,6 +4,7 @@
package com.vaadin.data.util;
import com.vaadin.data.Property;
+import com.vaadin.data.util.converter.Converter;
/**
* Formatting proxy for a {@link Property}.
@@ -29,16 +30,22 @@ import com.vaadin.data.Property;
* standard "1.0" notation with more zeroes.
* </p>
*
+ * @param T
+ * type of the underlying property (a PropertyFormatter is always a
+ * Property&lt;String&gt;)
+ *
+ * @deprecated Since 7.0 replaced by {@link Converter}
* @author Vaadin Ltd.
* @since 5.3.0
*/
@SuppressWarnings("serial")
-public abstract class PropertyFormatter extends AbstractProperty implements
- Property.Viewer, Property.ValueChangeListener,
+@Deprecated
+public abstract class PropertyFormatter<T> extends AbstractProperty<String>
+ implements Property.Viewer, Property.ValueChangeListener,
Property.ReadOnlyStatusChangeListener {
/** Datasource that stores the actual value. */
- Property dataSource;
+ Property<T> dataSource;
/**
* Construct a new {@code PropertyFormatter} that is not connected to any
@@ -57,7 +64,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* @param propertyDataSource
* to connect this property to.
*/
- public PropertyFormatter(Property propertyDataSource) {
+ public PropertyFormatter(Property<T> propertyDataSource) {
setPropertyDataSource(propertyDataSource);
}
@@ -68,7 +75,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* @return the current data source as a Property, or <code>null</code> if
* none defined.
*/
- public Property getPropertyDataSource() {
+ public Property<T> getPropertyDataSource() {
return dataSource;
}
@@ -99,7 +106,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
.removeListener(this);
}
readOnly = isReadOnly();
- prevValue = toString();
+ prevValue = getValue();
}
dataSource = newDataSource;
@@ -117,7 +124,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
if (isReadOnly() != readOnly) {
fireReadOnlyStatusChange();
}
- String newVal = toString();
+ String newVal = getValue();
if ((prevValue == null && newVal != null)
|| (prevValue != null && !prevValue.equals(newVal))) {
fireValueChange();
@@ -125,7 +132,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
}
/* Documented in the interface */
- public Class getType() {
+ public Class<String> getType() {
return String.class;
}
@@ -135,22 +142,8 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* @return If the datasource returns null, this is null. Otherwise this is
* String given by format().
*/
- public Object getValue() {
- return toString();
- }
-
- /**
- * Get the formatted value.
- *
- * @return If the datasource returns null, this is null. Otherwise this is
- * String given by format().
- */
- @Override
- public String toString() {
- if (dataSource == null) {
- return null;
- }
- Object value = dataSource.getValue();
+ public String getValue() {
+ T value = dataSource == null ? null : dataSource.getValue();
if (value == null) {
return null;
}
@@ -173,7 +166,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* datasource.
* @return
*/
- abstract public String format(Object value);
+ abstract public String format(T value);
/**
* Parse string and convert it to format compatible with datasource.
@@ -187,7 +180,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
* Any type of exception can be thrown to indicate that the
* conversion was not succesful.
*/
- abstract public Object parse(String formattedValue) throws Exception;
+ abstract public T parse(String formattedValue) throws Exception;
/**
* Sets the Property's read-only mode to the specified status.
@@ -202,8 +195,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements
}
}
- public void setValue(Object newValue) throws ReadOnlyException,
- ConversionException {
+ public void setValue(Object newValue) throws ReadOnlyException {
if (dataSource == null) {
return;
}
@@ -215,13 +207,11 @@ public abstract class PropertyFormatter extends AbstractProperty implements
} else {
try {
dataSource.setValue(parse(newValue.toString()));
- if (!newValue.equals(toString())) {
+ if (!newValue.equals(getValue())) {
fireValueChange();
}
- } catch (ConversionException e) {
- throw e;
} catch (Exception e) {
- throw new ConversionException(e);
+ throw new IllegalArgumentException("Could not parse value", e);
}
}
}
diff --git a/src/com/vaadin/data/util/PropertysetItem.java b/src/com/vaadin/data/util/PropertysetItem.java
index 04a7c66257..3270fa31f9 100644
--- a/src/com/vaadin/data/util/PropertysetItem.java
+++ b/src/com/vaadin/data/util/PropertysetItem.java
@@ -34,7 +34,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
/**
* Mapping from property id to property.
*/
- private HashMap<Object, Property> map = new HashMap<Object, Property>();
+ private HashMap<Object, Property<?>> map = new HashMap<Object, Property<?>>();
/**
* List of all property ids to maintain the order.
@@ -57,7 +57,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
* the identifier of the Property to get.
* @return the Property with the given ID or <code>null</code>
*/
- public Property getItemProperty(Object id) {
+ public Property<?> getItemProperty(Object id) {
return map.get(id);
}
@@ -143,7 +143,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
for (final Iterator<?> i = getItemPropertyIds().iterator(); i.hasNext();) {
final Object propertyId = i.next();
- retValue += getItemProperty(propertyId).toString();
+ retValue += getItemProperty(propertyId).getValue();
if (i.hasNext()) {
retValue += " ";
}
@@ -163,7 +163,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
* @VERSION@
* @since 3.0
*/
- private class PropertySetChangeEvent extends EventObject implements
+ private static class PropertySetChangeEvent extends EventObject implements
Item.PropertySetChangeEvent {
private PropertySetChangeEvent(Item source) {
@@ -262,7 +262,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier,
npsi.list = list != null ? (LinkedList<Object>) list.clone() : null;
npsi.propertySetChangeListeners = propertySetChangeListeners != null ? (LinkedList<PropertySetChangeListener>) propertySetChangeListeners
.clone() : null;
- npsi.map = (HashMap<Object, Property>) map.clone();
+ npsi.map = (HashMap<Object, Property<?>>) map.clone();
return npsi;
}
diff --git a/src/com/vaadin/data/util/QueryContainer.java b/src/com/vaadin/data/util/QueryContainer.java
index 2281343c30..7fef63e7f1 100644
--- a/src/com/vaadin/data/util/QueryContainer.java
+++ b/src/com/vaadin/data/util/QueryContainer.java
@@ -136,7 +136,8 @@ public class QueryContainer implements Container, Container.Ordered,
for (int i = 1; i <= count; i++) {
final String columnName = metadata.getColumnName(i);
list.add(columnName);
- final Property p = getContainerProperty(new Integer(1), columnName);
+ final Property<?> p = getContainerProperty(new Integer(1),
+ columnName);
propertyTypes.put(columnName,
p == null ? Object.class : p.getType());
}
@@ -228,7 +229,7 @@ public class QueryContainer implements Container, Container.Ordered,
* otherwise.
*/
- public synchronized Property getContainerProperty(Object itemId,
+ public synchronized Property<?> getContainerProperty(Object itemId,
Object propertyId) {
if (!(itemId instanceof Integer && propertyId instanceof String)) {
return null;
@@ -531,7 +532,7 @@ public class QueryContainer implements Container, Container.Ordered,
* identifier of the Property to get
* @return the Property with the given ID or <code>null</code>
*/
- public Property getItemProperty(Object propertyId) {
+ public Property<?> getItemProperty(Object propertyId) {
return getContainerProperty(id, propertyId);
}
diff --git a/src/com/vaadin/data/util/TextFileProperty.java b/src/com/vaadin/data/util/TextFileProperty.java
index cfa8d4fabf..5ebba98062 100644
--- a/src/com/vaadin/data/util/TextFileProperty.java
+++ b/src/com/vaadin/data/util/TextFileProperty.java
@@ -26,7 +26,7 @@ import java.nio.charset.Charset;
*
*/
@SuppressWarnings("serial")
-public class TextFileProperty extends AbstractProperty {
+public class TextFileProperty extends AbstractProperty<String> {
private File file;
private Charset charset = null;
@@ -64,7 +64,7 @@ public class TextFileProperty extends AbstractProperty {
*
* @see com.vaadin.data.Property#getType()
*/
- public Class<?> getType() {
+ public Class<String> getType() {
return String.class;
}
@@ -73,7 +73,7 @@ public class TextFileProperty extends AbstractProperty {
*
* @see com.vaadin.data.Property#getValue()
*/
- public Object getValue() {
+ public String getValue() {
if (file == null) {
return null;
}
diff --git a/src/com/vaadin/data/util/TransactionalPropertyWrapper.java b/src/com/vaadin/data/util/TransactionalPropertyWrapper.java
new file mode 100644
index 0000000000..06ec0935c3
--- /dev/null
+++ b/src/com/vaadin/data/util/TransactionalPropertyWrapper.java
@@ -0,0 +1,107 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.util;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeNotifier;
+
+/**
+ * Wrapper class that helps implement two-phase commit for a non-transactional
+ * property.
+ *
+ * When accessing the property through the wrapper, getting and setting the
+ * property value take place immediately. However, the wrapper keeps track of
+ * the old value of the property so that it can be set for the property in case
+ * of a roll-back. This can result in the underlying property value changing
+ * multiple times (first based on modifications made by the application, then
+ * back upon roll-back).
+ *
+ * Value change events on the {@link TransactionalPropertyWrapper} are only
+ * fired at the end of a successful transaction, whereas listeners attached to
+ * the underlying property may receive multiple value change events.
+ *
+ * @see com.vaadin.data.Property.Transactional
+ *
+ * @author Vaadin Ltd
+ * @version @version@
+ * @since 7.0
+ *
+ * @param <T>
+ */
+public class TransactionalPropertyWrapper<T> extends AbstractProperty<T>
+ implements ValueChangeNotifier, Property.Transactional<T> {
+
+ private Property<T> wrappedProperty;
+ private boolean inTransaction = false;
+ private boolean valueChangePending;
+ private T valueBeforeTransaction;
+
+ public TransactionalPropertyWrapper(Property<T> wrappedProperty) {
+ this.wrappedProperty = wrappedProperty;
+ if (wrappedProperty instanceof ValueChangeNotifier) {
+ ((ValueChangeNotifier) wrappedProperty)
+ .addListener(new ValueChangeListener() {
+
+ public void valueChange(ValueChangeEvent event) {
+ fireValueChange();
+ }
+ });
+ }
+ }
+
+ public Class getType() {
+ return wrappedProperty.getType();
+ }
+
+ public T getValue() {
+ return wrappedProperty.getValue();
+ }
+
+ public void setValue(Object newValue) throws ReadOnlyException {
+ // Causes a value change to be sent to this listener which in turn fires
+ // a new value change event for this property
+ wrappedProperty.setValue(newValue);
+ }
+
+ public void startTransaction() {
+ inTransaction = true;
+ valueBeforeTransaction = getValue();
+ }
+
+ public void commit() {
+ endTransaction();
+ }
+
+ public void rollback() {
+ try {
+ wrappedProperty.setValue(valueBeforeTransaction);
+ } finally {
+ valueChangePending = false;
+ endTransaction();
+ }
+ }
+
+ protected void endTransaction() {
+ inTransaction = false;
+ valueBeforeTransaction = null;
+ if (valueChangePending) {
+ fireValueChange();
+ }
+ }
+
+ @Override
+ protected void fireValueChange() {
+ if (inTransaction) {
+ valueChangePending = true;
+ } else {
+ super.fireValueChange();
+ }
+ }
+
+ public Property<T> getWrappedProperty() {
+ return wrappedProperty;
+ }
+
+}
diff --git a/src/com/vaadin/data/util/VaadinPropertyDescriptor.java b/src/com/vaadin/data/util/VaadinPropertyDescriptor.java
index 2a28671881..ee1e525540 100644
--- a/src/com/vaadin/data/util/VaadinPropertyDescriptor.java
+++ b/src/com/vaadin/data/util/VaadinPropertyDescriptor.java
@@ -39,5 +39,5 @@ public interface VaadinPropertyDescriptor<BT> extends Serializable {
* @param bean
* @return
*/
- public Property createProperty(BT bean);
-} \ No newline at end of file
+ public Property<?> createProperty(BT bean);
+}
diff --git a/src/com/vaadin/data/util/converter/Converter.java b/src/com/vaadin/data/util/converter/Converter.java
new file mode 100644
index 0000000000..b8c15e8cdc
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/Converter.java
@@ -0,0 +1,159 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.io.Serializable;
+import java.util.Locale;
+
+/**
+ * Interface that implements conversion between a model and a presentation type.
+ * <p>
+ * Typically {@link #convertToPresentation(Object, Locale)} and
+ * {@link #convertToModel(Object, Locale)} should be symmetric so that chaining
+ * these together returns the original result for all input but this is not a
+ * requirement.
+ * </p>
+ * <p>
+ * Converters must not have any side effects (never update UI from inside a
+ * converter).
+ * </p>
+ * <p>
+ * All Converters must be stateless and thread safe.
+ * </p>
+ * <p>
+ * If conversion of a value fails, a {@link ConversionException} is thrown.
+ * </p>
+ *
+ * @param <MODEL>
+ * The model type. Must be compatible with what
+ * {@link #getModelType()} returns.
+ * @param <PRESENTATION>
+ * The presentation type. Must be compatible with what
+ * {@link #getPresentationType()} returns.
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public interface Converter<PRESENTATION, MODEL> extends Serializable {
+
+ /**
+ * Converts the given value from target type to source type.
+ * <p>
+ * A converter can optionally use locale to do the conversion.
+ * </p>
+ * A converter should in most cases be symmetric so chaining
+ * {@link #convertToPresentation(Object, Locale)} and
+ * {@link #convertToModel(Object, Locale)} should return the original value.
+ *
+ * @param value
+ * The value to convert, compatible with the target type. Can be
+ * null
+ * @param locale
+ * The locale to use for conversion. Can be null.
+ * @return The converted value compatible with the source type
+ * @throws ConversionException
+ * If the value could not be converted
+ */
+ public MODEL convertToModel(PRESENTATION value, Locale locale)
+ throws ConversionException;
+
+ /**
+ * Converts the given value from source type to target type.
+ * <p>
+ * A converter can optionally use locale to do the conversion.
+ * </p>
+ * A converter should in most cases be symmetric so chaining
+ * {@link #convertToPresentation(Object, Locale)} and
+ * {@link #convertToModel(Object, Locale)} should return the original value.
+ *
+ * @param value
+ * The value to convert, compatible with the target type. Can be
+ * null
+ * @param locale
+ * The locale to use for conversion. Can be null.
+ * @return The converted value compatible with the source type
+ * @throws ConversionException
+ * If the value could not be converted
+ */
+ public PRESENTATION convertToPresentation(MODEL value, Locale locale)
+ throws ConversionException;
+
+ /**
+ * The source type of the converter.
+ *
+ * Values of this type can be passed to
+ * {@link #convertToPresentation(Object, Locale)}.
+ *
+ * @return The source type
+ */
+ public Class<MODEL> getModelType();
+
+ /**
+ * The target type of the converter.
+ *
+ * Values of this type can be passed to
+ * {@link #convertToModel(Object, Locale)}.
+ *
+ * @return The target type
+ */
+ public Class<PRESENTATION> getPresentationType();
+
+ /**
+ * An exception that signals that the value passed to
+ * {@link Converter#convertToPresentation(Object, Locale)} or
+ * {@link Converter#convertToModel(Object, Locale)} could not be converted.
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+ public static class ConversionException extends RuntimeException {
+
+ /**
+ * Constructs a new <code>ConversionException</code> without a detail
+ * message.
+ */
+ public ConversionException() {
+ }
+
+ /**
+ * Constructs a new <code>ConversionException</code> with the specified
+ * detail message.
+ *
+ * @param msg
+ * the detail message
+ */
+ public ConversionException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new {@code ConversionException} with the specified
+ * cause.
+ *
+ * @param cause
+ * The cause of the the exception
+ */
+ public ConversionException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a new <code>ConversionException</code> with the specified
+ * detail message and cause.
+ *
+ * @param message
+ * the detail message
+ * @param cause
+ * The cause of the the exception
+ */
+ public ConversionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+}
diff --git a/src/com/vaadin/data/util/converter/ConverterFactory.java b/src/com/vaadin/data/util/converter/ConverterFactory.java
new file mode 100644
index 0000000000..ed4ab41ac0
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/ConverterFactory.java
@@ -0,0 +1,23 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.io.Serializable;
+
+/**
+ * Factory interface for providing Converters based on a presentation type and a
+ * model type.
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ *
+ */
+public interface ConverterFactory extends Serializable {
+ public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> createConverter(
+ Class<PRESENTATION> presentationType, Class<MODEL> modelType);
+
+}
diff --git a/src/com/vaadin/data/util/converter/DateToLongConverter.java b/src/com/vaadin/data/util/converter/DateToLongConverter.java
new file mode 100644
index 0000000000..537800f617
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/DateToLongConverter.java
@@ -0,0 +1,68 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * A converter that converts from {@link Long} to {@link Date} and back.
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class DateToLongConverter implements Converter<Date, Long> {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object,
+ * java.util.Locale)
+ */
+ public Long convertToModel(Date value, Locale locale) {
+ if (value == null) {
+ return null;
+ }
+
+ return value.getTime();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang
+ * .Object, java.util.Locale)
+ */
+ public Date convertToPresentation(Long value, Locale locale) {
+ if (value == null) {
+ return null;
+ }
+
+ return new Date(value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getModelType()
+ */
+ public Class<Long> getModelType() {
+ return Long.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getPresentationType()
+ */
+ public Class<Date> getPresentationType() {
+ return Date.class;
+ }
+
+}
diff --git a/src/com/vaadin/data/util/converter/DefaultConverterFactory.java b/src/com/vaadin/data/util/converter/DefaultConverterFactory.java
new file mode 100644
index 0000000000..3ad7b6a85b
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/DefaultConverterFactory.java
@@ -0,0 +1,100 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.util.Date;
+import java.util.logging.Logger;
+
+import com.vaadin.Application;
+
+/**
+ * Default implementation of {@link ConverterFactory}. Provides converters for
+ * standard types like {@link String}, {@link Double} and {@link Date}. </p>
+ * <p>
+ * Custom converters can be provided by extending this class and using
+ * {@link Application#setConverterFactory(ConverterFactory)}.
+ * </p>
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class DefaultConverterFactory implements ConverterFactory {
+
+ private final static Logger log = Logger
+ .getLogger(DefaultConverterFactory.class.getName());
+
+ public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> createConverter(
+ Class<PRESENTATION> presentationType, Class<MODEL> modelType) {
+ Converter<PRESENTATION, MODEL> converter = findConverter(
+ presentationType, modelType);
+ if (converter != null) {
+ log.finest(getClass().getName() + " created a "
+ + converter.getClass());
+ return converter;
+ }
+
+ // Try to find a reverse converter
+ Converter<MODEL, PRESENTATION> reverseConverter = findConverter(
+ modelType, presentationType);
+ if (reverseConverter != null) {
+ log.finest(getClass().getName() + " created a reverse "
+ + reverseConverter.getClass());
+ return new ReverseConverter<PRESENTATION, MODEL>(reverseConverter);
+ }
+
+ log.finest(getClass().getName() + " could not find a converter for "
+ + presentationType.getName() + " to " + modelType.getName()
+ + " conversion");
+ return null;
+
+ }
+
+ protected <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> findConverter(
+ Class<PRESENTATION> presentationType, Class<MODEL> modelType) {
+ if (presentationType == String.class) {
+ // TextField converters and more
+ Converter<PRESENTATION, MODEL> converter = (Converter<PRESENTATION, MODEL>) createStringConverter(modelType);
+ if (converter != null) {
+ return converter;
+ }
+ } else if (presentationType == Date.class) {
+ // DateField converters and more
+ Converter<PRESENTATION, MODEL> converter = (Converter<PRESENTATION, MODEL>) createDateConverter(modelType);
+ if (converter != null) {
+ return converter;
+ }
+ }
+
+ return null;
+
+ }
+
+ protected Converter<Date, ?> createDateConverter(Class<?> sourceType) {
+ if (Long.class.isAssignableFrom(sourceType)) {
+ return new DateToLongConverter();
+ } else {
+ return null;
+ }
+ }
+
+ protected Converter<String, ?> createStringConverter(Class<?> sourceType) {
+ if (Double.class.isAssignableFrom(sourceType)) {
+ return new StringToDoubleConverter();
+ } else if (Integer.class.isAssignableFrom(sourceType)) {
+ return new StringToIntegerConverter();
+ } else if (Boolean.class.isAssignableFrom(sourceType)) {
+ return new StringToBooleanConverter();
+ } else if (Number.class.isAssignableFrom(sourceType)) {
+ return new StringToNumberConverter();
+ } else if (Date.class.isAssignableFrom(sourceType)) {
+ return new StringToDateConverter();
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/com/vaadin/data/util/converter/ReverseConverter.java b/src/com/vaadin/data/util/converter/ReverseConverter.java
new file mode 100644
index 0000000000..1c561f29e8
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/ReverseConverter.java
@@ -0,0 +1,80 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.util.Locale;
+
+/**
+ * A converter that wraps another {@link Converter} and reverses source and
+ * target types.
+ *
+ * @param <MODEL>
+ * The source type
+ * @param <PRESENTATION>
+ * The target type
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class ReverseConverter<PRESENTATION, MODEL> implements
+ Converter<PRESENTATION, MODEL> {
+
+ private Converter<MODEL, PRESENTATION> realConverter;
+
+ /**
+ * Creates a converter from source to target based on a converter that
+ * converts from target to source.
+ *
+ * @param converter
+ * The converter to use in a reverse fashion
+ */
+ public ReverseConverter(Converter<MODEL, PRESENTATION> converter) {
+ this.realConverter = converter;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#convertToModel(java
+ * .lang.Object, java.util.Locale)
+ */
+ public MODEL convertToModel(PRESENTATION value, Locale locale)
+ throws com.vaadin.data.util.converter.Converter.ConversionException {
+ return realConverter.convertToPresentation(value, locale);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang
+ * .Object, java.util.Locale)
+ */
+ public PRESENTATION convertToPresentation(MODEL value, Locale locale)
+ throws com.vaadin.data.util.converter.Converter.ConversionException {
+ return realConverter.convertToModel(value, locale);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getSourceType()
+ */
+ public Class<MODEL> getModelType() {
+ return realConverter.getPresentationType();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getTargetType()
+ */
+ public Class<PRESENTATION> getPresentationType() {
+ return realConverter.getModelType();
+ }
+
+}
diff --git a/src/com/vaadin/data/util/converter/StringToBooleanConverter.java b/src/com/vaadin/data/util/converter/StringToBooleanConverter.java
new file mode 100644
index 0000000000..96a3a3d071
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/StringToBooleanConverter.java
@@ -0,0 +1,104 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.util.Locale;
+
+/**
+ * A converter that converts from {@link String} to {@link Boolean} and back.
+ * The String representation is given by Boolean.toString().
+ * <p>
+ * Leading and trailing white spaces are ignored when converting from a String.
+ * </p>
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class StringToBooleanConverter implements Converter<String, Boolean> {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object,
+ * java.util.Locale)
+ */
+ public Boolean convertToModel(String value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ // Remove leading and trailing white space
+ value = value.trim();
+
+ if (getTrueString().equals(value)) {
+ return true;
+ } else if (getFalseString().equals(value)) {
+ return false;
+ } else {
+ throw new ConversionException("Cannot convert " + value + " to "
+ + getModelType().getName());
+ }
+ }
+
+ /**
+ * Gets the string representation for true. Default is "true".
+ *
+ * @return the string representation for true
+ */
+ protected String getTrueString() {
+ return Boolean.TRUE.toString();
+ }
+
+ /**
+ * Gets the string representation for false. Default is "false".
+ *
+ * @return the string representation for false
+ */
+ protected String getFalseString() {
+ return Boolean.FALSE.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang
+ * .Object, java.util.Locale)
+ */
+ public String convertToPresentation(Boolean value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+ if (value) {
+ return getTrueString();
+ } else {
+ return getFalseString();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getModelType()
+ */
+ public Class<Boolean> getModelType() {
+ return Boolean.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getPresentationType()
+ */
+ public Class<String> getPresentationType() {
+ return String.class;
+ }
+
+}
diff --git a/src/com/vaadin/data/util/converter/StringToDateConverter.java b/src/com/vaadin/data/util/converter/StringToDateConverter.java
new file mode 100644
index 0000000000..6f3c2e47f6
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/StringToDateConverter.java
@@ -0,0 +1,108 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.text.DateFormat;
+import java.text.ParsePosition;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * A converter that converts from {@link Date} to {@link String} and back. Uses
+ * the given locale and {@link DateFormat} for formatting and parsing.
+ * <p>
+ * Leading and trailing white spaces are ignored when converting from a String.
+ * </p>
+ * <p>
+ * Override and overwrite {@link #getFormat(Locale)} to use a different format.
+ * </p>
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class StringToDateConverter implements Converter<String, Date> {
+
+ /**
+ * Returns the format used by {@link #convertToPresentation(Date, Locale)}
+ * and {@link #convertToModel(String, Locale)}.
+ *
+ * @param locale
+ * The locale to use
+ * @return A DateFormat instance
+ */
+ protected DateFormat getFormat(Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+
+ DateFormat f = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
+ DateFormat.MEDIUM, locale);
+ f.setLenient(false);
+ return f;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object,
+ * java.util.Locale)
+ */
+ public Date convertToModel(String value, Locale locale)
+ throws com.vaadin.data.util.converter.Converter.ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ // Remove leading and trailing white space
+ value = value.trim();
+
+ ParsePosition parsePosition = new ParsePosition(0);
+ Date parsedValue = getFormat(locale).parse(value, parsePosition);
+ if (parsePosition.getIndex() != value.length()) {
+ throw new ConversionException("Could not convert '" + value
+ + "' to " + getModelType().getName());
+ }
+
+ return parsedValue;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang
+ * .Object, java.util.Locale)
+ */
+ public String convertToPresentation(Date value, Locale locale)
+ throws com.vaadin.data.util.converter.Converter.ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ return getFormat(locale).format(value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getModelType()
+ */
+ public Class<Date> getModelType() {
+ return Date.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getPresentationType()
+ */
+ public Class<String> getPresentationType() {
+ return String.class;
+ }
+
+}
diff --git a/src/com/vaadin/data/util/converter/StringToDoubleConverter.java b/src/com/vaadin/data/util/converter/StringToDoubleConverter.java
new file mode 100644
index 0000000000..60a38f4127
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/StringToDoubleConverter.java
@@ -0,0 +1,103 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+/**
+ * A converter that converts from {@link String} to {@link Double} and back.
+ * Uses the given locale and a {@link NumberFormat} instance for formatting and
+ * parsing.
+ * <p>
+ * Leading and trailing white spaces are ignored when converting from a String.
+ * </p>
+ * <p>
+ * Override and overwrite {@link #getFormat(Locale)} to use a different format.
+ * </p>
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class StringToDoubleConverter implements Converter<String, Double> {
+
+ /**
+ * Returns the format used by {@link #convertToPresentation(Double, Locale)}
+ * and {@link #convertToModel(String, Locale)}.
+ *
+ * @param locale
+ * The locale to use
+ * @return A NumberFormat instance
+ */
+ protected NumberFormat getFormat(Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+
+ return NumberFormat.getNumberInstance(locale);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object,
+ * java.util.Locale)
+ */
+ public Double convertToModel(String value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ // Remove leading and trailing white space
+ value = value.trim();
+
+ ParsePosition parsePosition = new ParsePosition(0);
+ Number parsedValue = getFormat(locale).parse(value, parsePosition);
+ if (parsePosition.getIndex() != value.length()) {
+ throw new ConversionException("Could not convert '" + value
+ + "' to " + getModelType().getName());
+ }
+ return parsedValue.doubleValue();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang
+ * .Object, java.util.Locale)
+ */
+ public String convertToPresentation(Double value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ return getFormat(locale).format(value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getModelType()
+ */
+ public Class<Double> getModelType() {
+ return Double.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getPresentationType()
+ */
+ public Class<String> getPresentationType() {
+ return String.class;
+ }
+}
diff --git a/src/com/vaadin/data/util/converter/StringToIntegerConverter.java b/src/com/vaadin/data/util/converter/StringToIntegerConverter.java
new file mode 100644
index 0000000000..e55feec3b6
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/StringToIntegerConverter.java
@@ -0,0 +1,84 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+/**
+ * A converter that converts from {@link String} to {@link Integer} and back.
+ * Uses the given locale and a {@link NumberFormat} instance for formatting and
+ * parsing.
+ * <p>
+ * Override and overwrite {@link #getFormat(Locale)} to use a different format.
+ * </p>
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class StringToIntegerConverter implements Converter<String, Integer> {
+
+ /**
+ * Returns the format used by
+ * {@link #convertToPresentation(Integer, Locale)} and
+ * {@link #convertToModel(String, Locale)}.
+ *
+ * @param locale
+ * The locale to use
+ * @return A NumberFormat instance
+ */
+ protected NumberFormat getFormat(Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ return NumberFormat.getIntegerInstance(locale);
+ }
+
+ public Integer convertToModel(String value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ // Remove leading and trailing white space
+ value = value.trim();
+
+ // Parse and detect errors. If the full string was not used, it is
+ // an error.
+ ParsePosition parsePosition = new ParsePosition(0);
+ Number parsedValue = getFormat(locale).parse(value, parsePosition);
+ if (parsePosition.getIndex() != value.length()) {
+ throw new ConversionException("Could not convert '" + value
+ + "' to " + getModelType().getName());
+ }
+
+ if (parsedValue == null) {
+ // Convert "" to null
+ return null;
+ }
+ return parsedValue.intValue();
+ }
+
+ public String convertToPresentation(Integer value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ return getFormat(locale).format(value);
+ }
+
+ public Class<Integer> getModelType() {
+ return Integer.class;
+ }
+
+ public Class<String> getPresentationType() {
+ return String.class;
+ }
+
+}
diff --git a/src/com/vaadin/data/util/converter/StringToNumberConverter.java b/src/com/vaadin/data/util/converter/StringToNumberConverter.java
new file mode 100644
index 0000000000..d1816007e7
--- /dev/null
+++ b/src/com/vaadin/data/util/converter/StringToNumberConverter.java
@@ -0,0 +1,107 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.util.converter;
+
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+/**
+ * A converter that converts from {@link Number} to {@link String} and back.
+ * Uses the given locale and {@link NumberFormat} for formatting and parsing.
+ * <p>
+ * Override and overwrite {@link #getFormat(Locale)} to use a different format.
+ * </p>
+ *
+ * @author Vaadin Ltd
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class StringToNumberConverter implements Converter<String, Number> {
+
+ /**
+ * Returns the format used by {@link #convertToPresentation(Number, Locale)}
+ * and {@link #convertToModel(String, Locale)}.
+ *
+ * @param locale
+ * The locale to use
+ * @return A NumberFormat instance
+ */
+ protected NumberFormat getFormat(Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+
+ return NumberFormat.getNumberInstance(locale);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object,
+ * java.util.Locale)
+ */
+ public Number convertToModel(String value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ // Remove leading and trailing white space
+ value = value.trim();
+
+ // Parse and detect errors. If the full string was not used, it is
+ // an error.
+ ParsePosition parsePosition = new ParsePosition(0);
+ Number parsedValue = getFormat(locale).parse(value, parsePosition);
+ if (parsePosition.getIndex() != value.length()) {
+ throw new ConversionException("Could not convert '" + value
+ + "' to " + getModelType().getName());
+ }
+
+ if (parsedValue == null) {
+ // Convert "" to null
+ return null;
+ }
+ return parsedValue;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang
+ * .Object, java.util.Locale)
+ */
+ public String convertToPresentation(Number value, Locale locale)
+ throws ConversionException {
+ if (value == null) {
+ return null;
+ }
+
+ return getFormat(locale).format(value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getModelType()
+ */
+ public Class<Number> getModelType() {
+ return Number.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.converter.Converter#getPresentationType()
+ */
+ public Class<String> getPresentationType() {
+ return String.class;
+ }
+
+}
diff --git a/src/com/vaadin/data/util/filter/Compare.java b/src/com/vaadin/data/util/filter/Compare.java
index fe7d908c93..111d95f055 100644
--- a/src/com/vaadin/data/util/filter/Compare.java
+++ b/src/com/vaadin/data/util/filter/Compare.java
@@ -228,7 +228,7 @@ public abstract class Compare implements Filter {
}
public boolean passesFilter(Object itemId, Item item) {
- final Property p = item.getItemProperty(getPropertyId());
+ final Property<?> p = item.getItemProperty(getPropertyId());
if (null == p) {
return false;
}
diff --git a/src/com/vaadin/data/util/filter/IsNull.java b/src/com/vaadin/data/util/filter/IsNull.java
index 0ae00d2e09..aad71a7c80 100644
--- a/src/com/vaadin/data/util/filter/IsNull.java
+++ b/src/com/vaadin/data/util/filter/IsNull.java
@@ -35,7 +35,7 @@ public final class IsNull implements Filter {
public boolean passesFilter(Object itemId, Item item)
throws UnsupportedOperationException {
- final Property p = item.getItemProperty(getPropertyId());
+ final Property<?> p = item.getItemProperty(getPropertyId());
if (null == p) {
return false;
}
diff --git a/src/com/vaadin/data/util/filter/SimpleStringFilter.java b/src/com/vaadin/data/util/filter/SimpleStringFilter.java
index 243571582e..6203251045 100644
--- a/src/com/vaadin/data/util/filter/SimpleStringFilter.java
+++ b/src/com/vaadin/data/util/filter/SimpleStringFilter.java
@@ -40,12 +40,16 @@ public final class SimpleStringFilter implements Filter {
}
public boolean passesFilter(Object itemId, Item item) {
- final Property p = item.getItemProperty(propertyId);
- if (p == null || p.toString() == null) {
+ final Property<?> p = item.getItemProperty(propertyId);
+ if (p == null) {
return false;
}
- final String value = ignoreCase ? p.toString().toLowerCase() : p
- .toString();
+ Object propertyValue = p.getValue();
+ if (propertyValue == null) {
+ return false;
+ }
+ final String value = ignoreCase ? propertyValue.toString()
+ .toLowerCase() : propertyValue.toString();
if (onlyMatchPrefix) {
if (!value.startsWith(filterString)) {
return false;
diff --git a/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java b/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java
index 9d88072c20..a74db6ce8a 100644
--- a/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java
+++ b/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java
@@ -3,7 +3,6 @@
*/
package com.vaadin.data.util.sqlcontainer;
-import java.lang.reflect.Constructor;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
@@ -69,8 +68,7 @@ final public class ColumnProperty implements Property {
return value;
}
- public void setValue(Object newValue) throws ReadOnlyException,
- ConversionException {
+ public void setValue(Object newValue) throws ReadOnlyException {
if (newValue == null && !nullable) {
throw new NotNullableException(
"Null values are not allowed for this property.");
@@ -109,19 +107,9 @@ final public class ColumnProperty implements Property {
}
}
- /*
- * If the type is not correct, try to generate it through a possibly
- * existing String constructor.
- */
if (!getType().isAssignableFrom(newValue.getClass())) {
- try {
- final Constructor<?> constr = getType().getConstructor(
- new Class[] { String.class });
- newValue = constr.newInstance(new Object[] { newValue
- .toString() });
- } catch (Exception e) {
- throw new ConversionException(e);
- }
+ throw new IllegalArgumentException(
+ "Illegal value type for ColumnProperty");
}
/*
@@ -168,13 +156,17 @@ final public class ColumnProperty implements Property {
return propertyId;
}
+ /**
+ * Returns the value of the Property in human readable textual format.
+ *
+ * @see java.lang.Object#toString()
+ * @deprecated get the string representation from the value
+ */
+ @Deprecated
@Override
public String toString() {
- Object val = getValue();
- if (val == null) {
- return null;
- }
- return val.toString();
+ throw new UnsupportedOperationException(
+ "Use ColumnProperty.getValue() instead of ColumnProperty.toString()");
}
public void setOwner(RowItem owner) {
diff --git a/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java b/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java
index 248b159aa9..adfd439ac8 100644
--- a/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java
+++ b/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java
@@ -3,6 +3,8 @@
*/
package com.vaadin.data.util.sqlcontainer;
+import com.vaadin.data.util.sqlcontainer.query.TableQuery;
+
/**
* An OptimisticLockException is thrown when trying to update or delete a row
* that has been changed since last read from the database.
@@ -12,7 +14,7 @@ package com.vaadin.data.util.sqlcontainer;
* configuration. In order to turn on optimistic locking, you need to specify
* the version column in your TableQuery instance.
*
- * @see com.vaadin.addon.sqlcontainer.query.TableQuery#setVersionColumn(String)
+ * @see TableQuery#setVersionColumn(String)
*
* @author Jonatan Kronqvist / Vaadin Ltd
*/
diff --git a/src/com/vaadin/data/util/sqlcontainer/RowItem.java b/src/com/vaadin/data/util/sqlcontainer/RowItem.java
index 3bd73bc48f..adededb65c 100644
--- a/src/com/vaadin/data/util/sqlcontainer/RowItem.java
+++ b/src/com/vaadin/data/util/sqlcontainer/RowItem.java
@@ -48,7 +48,7 @@ public final class RowItem implements Item {
this.id = id;
}
- public Property getItemProperty(Object id) {
+ public Property<?> getItemProperty(Object id) {
if (id instanceof String && id != null) {
for (ColumnProperty cp : properties) {
if (id.equals(cp.getPropertyId())) {
@@ -113,7 +113,8 @@ public final class RowItem implements Item {
s.append("|");
s.append(propId.toString());
s.append(":");
- s.append(getItemProperty(propId).toString());
+ Object value = getItemProperty(propId).getValue();
+ s.append((null != value) ? value.toString() : null);
}
return s.toString();
}
diff --git a/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
index 7eb67437e0..3bf33defd5 100644
--- a/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
+++ b/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
@@ -227,7 +227,7 @@ public class SQLContainer implements Container, Container.Filterable,
* @see com.vaadin.data.Container#getContainerProperty(java.lang.Object,
* java.lang.Object)
*/
- public Property getContainerProperty(Object itemId, Object propertyId) {
+ public Property<?> getContainerProperty(Object itemId, Object propertyId) {
Item item = getItem(itemId);
if (item == null) {
return null;
@@ -1435,7 +1435,7 @@ public class SQLContainer implements Container, Container.Filterable,
* Simple ItemSetChangeEvent implementation.
*/
@SuppressWarnings("serial")
- public class ItemSetChangeEvent extends EventObject implements
+ public static class ItemSetChangeEvent extends EventObject implements
Container.ItemSetChangeEvent {
private ItemSetChangeEvent(SQLContainer source) {
@@ -1640,4 +1640,4 @@ public class SQLContainer implements Container, Container.Filterable,
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java b/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java
index 7dcab29611..56a8455a16 100644
--- a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java
+++ b/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java
@@ -178,15 +178,14 @@ public class FreeformQuery implements QueryDelegate {
/**
* Fetches the results for the query. This implementation always fetches the
- * entire record set, ignoring the offset and pagelength parameters. In
+ * entire record set, ignoring the offset and page length parameters. In
* order to support lazy loading of records, you must supply a
* FreeformQueryDelegate that implements the
* FreeformQueryDelegate.getQueryString(int,int) method.
*
* @throws SQLException
*
- * @see com.vaadin.addon.sqlcontainer.query.FreeformQueryDelegate#getQueryString(int,
- * int) {@inheritDoc}
+ * @see FreeformQueryDelegate#getQueryString(int, int)
*/
@SuppressWarnings("deprecation")
public ResultSet getResults(int offset, int pagelength) throws SQLException {
@@ -249,8 +248,8 @@ public class FreeformQuery implements QueryDelegate {
* (non-Javadoc)
*
* @see
- * com.vaadin.addon.sqlcontainer.query.QueryDelegate#setFilters(java.util
- * .List)
+ * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#setFilters(java
+ * .util.List)
*/
public void setFilters(List<Filter> filters)
throws UnsupportedOperationException {
@@ -262,6 +261,13 @@ public class FreeformQuery implements QueryDelegate {
}
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#setOrderBy(java
+ * .util.List)
+ */
public void setOrderBy(List<OrderBy> orderBys)
throws UnsupportedOperationException {
if (delegate != null) {
@@ -272,6 +278,13 @@ public class FreeformQuery implements QueryDelegate {
}
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#storeRow(com.vaadin
+ * .data.util.sqlcontainer.RowItem)
+ */
public int storeRow(RowItem row) throws SQLException {
if (activeConnection == null) {
throw new IllegalStateException("No transaction is active!");
@@ -287,6 +300,13 @@ public class FreeformQuery implements QueryDelegate {
}
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#removeRow(com.vaadin
+ * .data.util.sqlcontainer.RowItem)
+ */
public boolean removeRow(RowItem row) throws SQLException {
if (activeConnection == null) {
throw new IllegalStateException("No transaction is active!");
@@ -302,6 +322,12 @@ public class FreeformQuery implements QueryDelegate {
}
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#beginTransaction()
+ */
public synchronized void beginTransaction()
throws UnsupportedOperationException, SQLException {
if (activeConnection != null) {
@@ -311,6 +337,11 @@ public class FreeformQuery implements QueryDelegate {
activeConnection.setAutoCommit(false);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#commit()
+ */
public synchronized void commit() throws UnsupportedOperationException,
SQLException {
if (activeConnection == null) {
@@ -323,6 +354,11 @@ public class FreeformQuery implements QueryDelegate {
activeConnection = null;
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#rollback()
+ */
public synchronized void rollback() throws UnsupportedOperationException,
SQLException {
if (activeConnection == null) {
@@ -333,6 +369,13 @@ public class FreeformQuery implements QueryDelegate {
activeConnection = null;
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#getPrimaryKeyColumns
+ * ()
+ */
public List<String> getPrimaryKeyColumns() {
return primaryKeyColumns;
}
@@ -357,9 +400,8 @@ public class FreeformQuery implements QueryDelegate {
* getContainsRowQueryString method in FreeformQueryDelegate and this will
* be used instead of the logic.
*
- * @see com.vaadin.addon.sqlcontainer.query.FreeformQueryDelegate#getContainsRowQueryString(Object...)
+ * @see FreeformQueryDelegate#getContainsRowQueryString(Object...)
*
- * {@inheritDoc}
*/
@SuppressWarnings("deprecation")
public boolean containsRowWithKey(Object... keys) throws SQLException {
diff --git a/src/com/vaadin/data/validator/AbstractStringValidator.java b/src/com/vaadin/data/validator/AbstractStringValidator.java
index 3bc66b3a73..5267cc7b7b 100644
--- a/src/com/vaadin/data/validator/AbstractStringValidator.java
+++ b/src/com/vaadin/data/validator/AbstractStringValidator.java
@@ -4,9 +4,7 @@
package com.vaadin.data.validator;
/**
- * Validator base class for validating strings. See
- * {@link com.vaadin.data.validator.AbstractValidator} for more information.
- *
+ * Validator base class for validating strings.
* <p>
* To include the value that failed validation in the exception message you can
* use "{0}" in the error message. This will be replaced with the failed value
@@ -15,12 +13,11 @@ package com.vaadin.data.validator;
* </p>
*
* @author Vaadin Ltd.
- * @version
- * @VERSION@
+ * @version @VERSION@
* @since 5.4
*/
@SuppressWarnings("serial")
-public abstract class AbstractStringValidator extends AbstractValidator {
+public abstract class AbstractStringValidator extends AbstractValidator<String> {
/**
* Constructs a validator for strings.
@@ -38,35 +35,8 @@ public abstract class AbstractStringValidator extends AbstractValidator {
super(errorMessage);
}
- /**
- * Tests if the given value is a valid string.
- * <p>
- * Null values are always accepted. Values that are not {@link String}s are
- * converted using {@link #toString()}. Then {@link #isValidString(String)}
- * is used to validate the value.
- * </p>
- *
- * @param value
- * the value to check
- * @return true if the value (or its toString()) is a valid string, false
- * otherwise
- */
- public boolean isValid(Object value) {
- if (value == null) {
- return true;
- }
- if (!(value instanceof String)) {
- value = String.valueOf(value);
- }
- return isValidString((String) value);
+ @Override
+ public Class<String> getType() {
+ return String.class;
}
-
- /**
- * Checks if the given string is valid.
- *
- * @param value
- * String to check. Can never be null.
- * @return true if the string is valid, false otherwise
- */
- protected abstract boolean isValidString(String value);
}
diff --git a/src/com/vaadin/data/validator/AbstractValidator.java b/src/com/vaadin/data/validator/AbstractValidator.java
index 5c8dd9b31a..27eaaca485 100644
--- a/src/com/vaadin/data/validator/AbstractValidator.java
+++ b/src/com/vaadin/data/validator/AbstractValidator.java
@@ -7,8 +7,8 @@ import com.vaadin.data.Validator;
/**
* Abstract {@link com.vaadin.data.Validator Validator} implementation that
- * provides a basic Validator implementation except the {@link #isValid(Object)}
- * method. Sub-classes need to implement the {@link #isValid(Object)} method.
+ * provides a basic Validator implementation except the
+ * {@link #isValidValue(Object)} method.
* <p>
* To include the value that failed validation in the exception message you can
* use "{0}" in the error message. This will be replaced with the failed value
@@ -21,14 +21,20 @@ import com.vaadin.data.Validator;
* {@link InvalidValueException#getHtmlMessage()} and throw such exceptions from
* {@link #validate(Object)}.
* </p>
+ * <p>
+ * Since Vaadin 7, subclasses can either implement {@link #validate(Object)}
+ * directly or implement {@link #isValidValue(Object)} when migrating legacy
+ * applications. To check validity, {@link #validate(Object)} should be used.
+ * </p>
*
+ * @param <T>
+ * The type
* @author Vaadin Ltd.
* @version
* @VERSION@
* @since 5.4
*/
-@SuppressWarnings("serial")
-public abstract class AbstractValidator implements Validator {
+public abstract class AbstractValidator<T> implements Validator {
/**
* Error message that is included in an {@link InvalidValueException} if
@@ -47,14 +53,65 @@ public abstract class AbstractValidator implements Validator {
this.errorMessage = errorMessage;
}
+ /**
+ * Since Vaadin 7, subclasses of AbstractValidator should override
+ * {@link #isValidValue(Object)} or {@link #validate(Object)} instead of
+ * {@link #isValid(Object)}. {@link #validate(Object)} should normally be
+ * used to check values.
+ *
+ * @param value
+ * @return true if the value is valid
+ */
+ public boolean isValid(Object value) {
+ try {
+ validate(value);
+ return true;
+ } catch (InvalidValueException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Internally check the validity of a value. This method can be used to
+ * perform validation in subclasses if customization of the error message is
+ * not needed. Otherwise, subclasses should override
+ * {@link #validate(Object)} and the return value of this method is ignored.
+ *
+ * This method should not be called from outside the validator class itself.
+ *
+ * @param value
+ * @return
+ */
+ protected abstract boolean isValidValue(T value);
+
public void validate(Object value) throws InvalidValueException {
- if (!isValid(value)) {
- String message = getErrorMessage().replace("{0}", String.valueOf(value));
+ // isValidType ensures that value can safely be cast to TYPE
+ if (!isValidType(value) || !isValidValue((T) value)) {
+ String message = getErrorMessage().replace("{0}",
+ String.valueOf(value));
throw new InvalidValueException(message);
}
}
/**
+ * Checks the type of the value to validate to ensure it conforms with
+ * getType. Enables sub classes to handle the specific type instead of
+ * Object.
+ *
+ * @param value
+ * The value to check
+ * @return true if the value can safely be cast to the type specified by
+ * {@link #getType()}
+ */
+ protected boolean isValidType(Object value) {
+ if (value == null) {
+ return true;
+ }
+
+ return getType().isAssignableFrom(value.getClass());
+ }
+
+ /**
* Returns the message to be included in the exception in case the value
* does not validate.
*
@@ -76,4 +133,6 @@ public abstract class AbstractValidator implements Validator {
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
+
+ public abstract Class<T> getType();
}
diff --git a/src/com/vaadin/data/validator/BeanValidator.java b/src/com/vaadin/data/validator/BeanValidator.java
new file mode 100644
index 0000000000..817df85248
--- /dev/null
+++ b/src/com/vaadin/data/validator/BeanValidator.java
@@ -0,0 +1,173 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.data.validator;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.MessageInterpolator.Context;
+import javax.validation.Validation;
+import javax.validation.ValidatorFactory;
+import javax.validation.metadata.ConstraintDescriptor;
+
+import com.vaadin.data.Validator;
+
+/**
+ * Vaadin {@link Validator} using the JSR-303 (javax.validation)
+ * annotation-based bean validation.
+ *
+ * The annotations of the fields of the beans are used to determine the
+ * validation to perform.
+ *
+ * Note that a JSR-303 implementation (e.g. Hibernate Validator or Apache Bean
+ * Validation - formerly agimatec validation) must be present on the project
+ * classpath when using bean validation.
+ *
+ * @since 7.0
+ *
+ * @author Petri Hakala
+ * @author Henri Sara
+ */
+public class BeanValidator implements Validator {
+
+ private static final long serialVersionUID = 1L;
+ private static ValidatorFactory factory;
+
+ private transient javax.validation.Validator javaxBeanValidator;
+ private String propertyName;
+ private Class<?> beanClass;
+ private Locale locale;
+
+ /**
+ * Simple implementation of a message interpolator context that returns
+ * fixed values.
+ */
+ protected static class SimpleContext implements Context, Serializable {
+
+ private final Object value;
+ private final ConstraintDescriptor<?> descriptor;
+
+ /**
+ * Create a simple immutable message interpolator context.
+ *
+ * @param value
+ * value being validated
+ * @param descriptor
+ * ConstraintDescriptor corresponding to the constraint being
+ * validated
+ */
+ public SimpleContext(Object value, ConstraintDescriptor<?> descriptor) {
+ this.value = value;
+ this.descriptor = descriptor;
+ }
+
+ public ConstraintDescriptor<?> getConstraintDescriptor() {
+ return descriptor;
+ }
+
+ public Object getValidatedValue() {
+ return value;
+ }
+
+ }
+
+ /**
+ * Creates a Vaadin {@link Validator} utilizing JSR-303 bean validation.
+ *
+ * @param beanClass
+ * bean class based on which the validation should be performed
+ * @param propertyName
+ * property to validate
+ */
+ public BeanValidator(Class<?> beanClass, String propertyName) {
+ this.beanClass = beanClass;
+ this.propertyName = propertyName;
+ locale = Locale.getDefault();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.Validator#validate(java.lang.Object)
+ */
+ public void validate(final Object value) throws InvalidValueException {
+ Set<?> violations = getJavaxBeanValidator().validateValue(beanClass,
+ propertyName, value);
+ if (violations.size() > 0) {
+ List<String> exceptions = new ArrayList<String>();
+ for (Object v : violations) {
+ final ConstraintViolation<?> violation = (ConstraintViolation<?>) v;
+ String msg = getJavaxBeanValidatorFactory()
+ .getMessageInterpolator().interpolate(
+ violation.getMessageTemplate(),
+ new SimpleContext(value, violation
+ .getConstraintDescriptor()), locale);
+ exceptions.add(msg);
+ }
+ StringBuilder b = new StringBuilder();
+ for (int i = 0; i < exceptions.size(); i++) {
+ if (i != 0) {
+ b.append("<br/>");
+ }
+ b.append(exceptions.get(i));
+ }
+ throw new InvalidValueException(b.toString());
+ }
+ }
+
+ /**
+ * Sets the locale used for validation error messages.
+ *
+ * Revalidation is not automatically triggered by setting the locale.
+ *
+ * @param locale
+ */
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+ /**
+ * Gets the locale used for validation error messages.
+ *
+ * @return locale used for validation
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Returns the underlying JSR-303 bean validator factory used. A factory is
+ * created using {@link Validation} if necessary.
+ *
+ * @return {@link ValidatorFactory} to use
+ */
+ protected static ValidatorFactory getJavaxBeanValidatorFactory() {
+ if (factory == null) {
+ factory = Validation.buildDefaultValidatorFactory();
+ }
+
+ return factory;
+ }
+
+ /**
+ * Returns a shared Validator instance to use. An instance is created using
+ * the validator factory if necessary and thereafter reused by the
+ * {@link BeanValidator} instance.
+ *
+ * @return the JSR-303 {@link javax.validation.Validator} to use
+ */
+ protected javax.validation.Validator getJavaxBeanValidator() {
+ if (javaxBeanValidator == null) {
+ javaxBeanValidator = getJavaxBeanValidatorFactory().getValidator();
+ }
+
+ return javaxBeanValidator;
+ }
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/data/validator/CompositeValidator.java b/src/com/vaadin/data/validator/CompositeValidator.java
index 6227a3a2d8..956d773032 100644
--- a/src/com/vaadin/data/validator/CompositeValidator.java
+++ b/src/com/vaadin/data/validator/CompositeValidator.java
@@ -19,37 +19,44 @@ import com.vaadin.data.Validator;
* <code>AND</code> and <code>OR</code>.
*
* @author Vaadin Ltd.
- * @version
- * @VERSION@
+ * @version @VERSION@
* @since 3.0
*/
@SuppressWarnings("serial")
-public class CompositeValidator extends AbstractValidator {
+public class CompositeValidator implements Validator {
- /**
- * The validators are combined with <code>AND</code> clause: validity of the
- * composite implies validity of the all validators it is composed of must
- * be valid.
- */
- public static final int MODE_AND = 0;
+ public enum CombinationMode {
+ /**
+ * The validators are combined with <code>AND</code> clause: validity of
+ * the composite implies validity of the all validators it is composed
+ * of must be valid.
+ */
+ AND,
+ /**
+ * The validators are combined with <code>OR</code> clause: validity of
+ * the composite implies that some of validators it is composed of must
+ * be valid.
+ */
+ OR;
+ }
/**
- * The validators are combined with <code>OR</code> clause: validity of the
- * composite implies that some of validators it is composed of must be
- * valid.
+ * @deprecated from 7.0, use {@link CombinationMode#AND} instead    
*/
- public static final int MODE_OR = 1;
-
+ @Deprecated
+ public static final CombinationMode MODE_AND = CombinationMode.AND;
/**
- * The validators are combined with and clause: validity of the composite
- * implies validity of the all validators it is composed of
+ * @deprecated from 7.0, use {@link CombinationMode#OR} instead    
*/
- public static final int MODE_DEFAULT = MODE_AND;
+ @Deprecated
+ public static final CombinationMode MODE_OR = CombinationMode.OR;
+
+ private String errorMessage;
/**
* Operation mode.
*/
- private int mode = MODE_DEFAULT;
+ private CombinationMode mode = CombinationMode.AND;
/**
* List of contained validators.
@@ -61,14 +68,17 @@ public class CompositeValidator extends AbstractValidator {
* message.
*/
public CompositeValidator() {
- super("");
+ this(CombinationMode.AND, "");
}
/**
* Constructs a composite validator in given mode.
+ *
+ * @param mode
+ * @param errorMessage
*/
- public CompositeValidator(int mode, String errorMessage) {
- super(errorMessage);
+ public CompositeValidator(CombinationMode mode, String errorMessage) {
+ setErrorMessage(errorMessage);
setMode(mode);
}
@@ -91,16 +101,15 @@ public class CompositeValidator extends AbstractValidator {
* @throws Validator.InvalidValueException
* if the value is not valid.
*/
- @Override
public void validate(Object value) throws Validator.InvalidValueException {
switch (mode) {
- case MODE_AND:
+ case AND:
for (Validator validator : validators) {
validator.validate(value);
}
return;
- case MODE_OR:
+ case OR:
Validator.InvalidValueException first = null;
for (Validator v : validators) {
try {
@@ -122,65 +131,32 @@ public class CompositeValidator extends AbstractValidator {
throw first;
}
}
- throw new IllegalStateException(
- "The validator is in unsupported operation mode");
- }
-
- /**
- * Checks the validity of the the given value. The value is valid, if:
- * <ul>
- * <li><code>MODE_AND</code>: All of the sub-validators are valid
- * <li><code>MODE_OR</code>: Any of the sub-validators are valid
- * </ul>
- *
- * @param value
- * the value to check.
- */
- public boolean isValid(Object value) {
- switch (mode) {
- case MODE_AND:
- for (Validator v : validators) {
- if (!v.isValid(value)) {
- return false;
- }
- }
- return true;
-
- case MODE_OR:
- for (Validator v : validators) {
- if (v.isValid(value)) {
- return true;
- }
- }
- return false;
- }
- throw new IllegalStateException(
- "The valitor is in unsupported operation mode");
}
/**
* Gets the mode of the validator.
*
- * @return Operation mode of the validator: <code>MODE_AND</code> or
- * <code>MODE_OR</code>.
+ * @return Operation mode of the validator: {@link CombinationMode#AND} or
+ * {@link CombinationMode#OR}.
*/
- public final int getMode() {
+ public final CombinationMode getMode() {
return mode;
}
/**
* Sets the mode of the validator. The valid modes are:
* <ul>
- * <li><code>MODE_AND</code> (default)
- * <li><code>MODE_OR</code>
+ * <li>{@link CombinationMode#AND} (default)
+ * <li>{@link CombinationMode#OR}
* </ul>
*
* @param mode
* the mode to set.
*/
- public void setMode(int mode) {
- if (mode != MODE_AND && mode != MODE_OR) {
- throw new IllegalArgumentException("Mode " + mode + " unsupported");
+ public void setMode(CombinationMode mode) {
+ if (mode == null) {
+ throw new IllegalArgumentException(
+ "The validator can't be set to null");
}
this.mode = mode;
}
@@ -189,10 +165,9 @@ public class CompositeValidator extends AbstractValidator {
* Gets the error message for the composite validator. If the error message
* is null, original error messages of the sub-validators are used instead.
*/
- @Override
public String getErrorMessage() {
- if (super.getErrorMessage() != null) {
- return super.getErrorMessage();
+ if (errorMessage != null) {
+ return errorMessage;
}
// TODO Return composite error message
@@ -240,11 +215,14 @@ public class CompositeValidator extends AbstractValidator {
* validators of given type null is returned.
* </p>
*
+ * @param validatorType
+ * The type of validators to return
+ *
* @return Collection<Validator> of validators compatible with given type
- * that must apply or null if none fould.
+ * that must apply or null if none found.
*/
public Collection<Validator> getSubValidators(Class validatorType) {
- if (mode != MODE_AND) {
+ if (mode != CombinationMode.AND) {
return null;
}
@@ -266,4 +244,15 @@ public class CompositeValidator extends AbstractValidator {
return found.isEmpty() ? null : found;
}
+ /**
+ * Sets the message to be included in the exception in case the value does
+ * not validate. The exception message is typically shown to the end user.
+ *
+ * @param errorMessage
+ * the error message.
+ */
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
}
diff --git a/src/com/vaadin/data/validator/DateRangeValidator.java b/src/com/vaadin/data/validator/DateRangeValidator.java
new file mode 100644
index 0000000000..24f3d3ce10
--- /dev/null
+++ b/src/com/vaadin/data/validator/DateRangeValidator.java
@@ -0,0 +1,51 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.validator;
+
+import java.util.Date;
+
+import com.vaadin.ui.DateField.Resolution;
+
+/**
+ * Validator for validating that a Date is inside a given range.
+ *
+ * <p>
+ * Note that the comparison is done directly on the Date object so take care
+ * that the hours/minutes/seconds/milliseconds of the min/max values are
+ * properly set.
+ * </p>
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class DateRangeValidator extends RangeValidator<Date> {
+
+ /**
+ * Creates a validator for checking that an Date is within a given range.
+ * <p>
+ * By default the range is inclusive i.e. both minValue and maxValue are
+ * valid values. Use {@link #setMinValueIncluded(boolean)} or
+ * {@link #setMaxValueIncluded(boolean)} to change it.
+ * </p>
+ * <p>
+ * Note that the comparison is done directly on the Date object so take care
+ * that the hours/minutes/seconds/milliseconds of the min/max values are
+ * properly set.
+ * </p>
+ *
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ * @param minValue
+ * The minimum value to accept or null for no limit
+ * @param maxValue
+ * The maximum value to accept or null for no limit
+ */
+ public DateRangeValidator(String errorMessage, Date minValue,
+ Date maxValue, Resolution resolution) {
+ super(errorMessage, Date.class, minValue, maxValue);
+ }
+
+}
diff --git a/src/com/vaadin/data/validator/DoubleRangeValidator.java b/src/com/vaadin/data/validator/DoubleRangeValidator.java
new file mode 100644
index 0000000000..91fcf004af
--- /dev/null
+++ b/src/com/vaadin/data/validator/DoubleRangeValidator.java
@@ -0,0 +1,36 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.validator;
+
+/**
+ * Validator for validating that a {@link Double} is inside a given range.
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+@SuppressWarnings("serial")
+public class DoubleRangeValidator extends RangeValidator<Double> {
+
+ /**
+ * Creates a validator for checking that an Double is within a given range.
+ *
+ * By default the range is inclusive i.e. both minValue and maxValue are
+ * valid values. Use {@link #setMinValueIncluded(boolean)} or
+ * {@link #setMaxValueIncluded(boolean)} to change it.
+ *
+ *
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ * @param minValue
+ * The minimum value to accept or null for no limit
+ * @param maxValue
+ * The maximum value to accept or null for no limit
+ */
+ public DoubleRangeValidator(String errorMessage, Double minValue, Double maxValue) {
+ super(errorMessage, Double.class, minValue, maxValue);
+ }
+
+}
diff --git a/src/com/vaadin/data/validator/DoubleValidator.java b/src/com/vaadin/data/validator/DoubleValidator.java
index e90919c17d..18f1909add 100644
--- a/src/com/vaadin/data/validator/DoubleValidator.java
+++ b/src/com/vaadin/data/validator/DoubleValidator.java
@@ -12,7 +12,9 @@ package com.vaadin.data.validator;
* @version
* @VERSION@
* @since 5.4
+ * @deprecated in Vaadin 7.0. Use an Double converter on the field instead.
*/
+@Deprecated
@SuppressWarnings("serial")
public class DoubleValidator extends AbstractStringValidator {
@@ -22,13 +24,17 @@ public class DoubleValidator extends AbstractStringValidator {
*
* @param errorMessage
* the message to display in case the value does not validate.
+ * @deprecated in Vaadin 7.0. Use a Double converter on the field instead
+ * and/or use a {@link DoubleRangeValidator} for validating that
+ * the value is inside a given range.
*/
+ @Deprecated
public DoubleValidator(String errorMessage) {
super(errorMessage);
}
@Override
- protected boolean isValidString(String value) {
+ protected boolean isValidValue(String value) {
try {
Double.parseDouble(value);
return true;
@@ -37,4 +43,16 @@ public class DoubleValidator extends AbstractStringValidator {
}
}
+ @Override
+ public void validate(Object value) throws InvalidValueException {
+ if (value != null && value instanceof Double) {
+ // Allow Doubles to pass through the validator for easier
+ // migration. Otherwise a TextField connected to an double property
+ // with a DoubleValidator will fail.
+ return;
+ }
+
+ super.validate(value);
+ }
+
}
diff --git a/src/com/vaadin/data/validator/IntegerRangeValidator.java b/src/com/vaadin/data/validator/IntegerRangeValidator.java
new file mode 100644
index 0000000000..c171dd97d8
--- /dev/null
+++ b/src/com/vaadin/data/validator/IntegerRangeValidator.java
@@ -0,0 +1,37 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.validator;
+
+/**
+ * Validator for validating that an {@link Integer} is inside a given range.
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.4
+ */
+@SuppressWarnings("serial")
+public class IntegerRangeValidator extends RangeValidator<Integer> {
+
+ /**
+ * Creates a validator for checking that an Integer is within a given range.
+ *
+ * By default the range is inclusive i.e. both minValue and maxValue are
+ * valid values. Use {@link #setMinValueIncluded(boolean)} or
+ * {@link #setMaxValueIncluded(boolean)} to change it.
+ *
+ *
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ * @param minValue
+ * The minimum value to accept or null for no limit
+ * @param maxValue
+ * The maximum value to accept or null for no limit
+ */
+ public IntegerRangeValidator(String errorMessage, Integer minValue,
+ Integer maxValue) {
+ super(errorMessage, Integer.class, minValue, maxValue);
+ }
+
+}
diff --git a/src/com/vaadin/data/validator/IntegerValidator.java b/src/com/vaadin/data/validator/IntegerValidator.java
index 50b45b90ce..88ae9f3f0b 100644
--- a/src/com/vaadin/data/validator/IntegerValidator.java
+++ b/src/com/vaadin/data/validator/IntegerValidator.java
@@ -12,8 +12,10 @@ package com.vaadin.data.validator;
* @version
* @VERSION@
* @since 5.4
+ * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead.
*/
@SuppressWarnings("serial")
+@Deprecated
public class IntegerValidator extends AbstractStringValidator {
/**
@@ -22,14 +24,18 @@ public class IntegerValidator extends AbstractStringValidator {
*
* @param errorMessage
* the message to display in case the value does not validate.
+ * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead
+ * and/or use an {@link IntegerRangeValidator} for validating
+ * that the value is inside a given range.
*/
+ @Deprecated
public IntegerValidator(String errorMessage) {
super(errorMessage);
}
@Override
- protected boolean isValidString(String value) {
+ protected boolean isValidValue(String value) {
try {
Integer.parseInt(value);
return true;
@@ -38,4 +44,15 @@ public class IntegerValidator extends AbstractStringValidator {
}
}
+ @Override
+ public void validate(Object value) throws InvalidValueException {
+ if (value != null && value instanceof Integer) {
+ // Allow Integers to pass through the validator for easier
+ // migration. Otherwise a TextField connected to an integer property
+ // with an IntegerValidator will fail.
+ return;
+ }
+
+ super.validate(value);
+ }
}
diff --git a/src/com/vaadin/data/validator/NullValidator.java b/src/com/vaadin/data/validator/NullValidator.java
index 77f9a606b4..62b2580d48 100644
--- a/src/com/vaadin/data/validator/NullValidator.java
+++ b/src/com/vaadin/data/validator/NullValidator.java
@@ -51,17 +51,6 @@ public class NullValidator implements Validator {
}
/**
- * Tests if the given value is valid.
- *
- * @param value
- * the value to validate.
- * @returns <code>true</code> for valid value, otherwise <code>false</code>.
- */
- public boolean isValid(Object value) {
- return onlyNullAllowed ? value == null : value != null;
- }
-
- /**
* Returns <code>true</code> if nulls are allowed otherwise
* <code>false</code>.
*/
diff --git a/src/com/vaadin/data/validator/RangeValidator.java b/src/com/vaadin/data/validator/RangeValidator.java
new file mode 100644
index 0000000000..433271274f
--- /dev/null
+++ b/src/com/vaadin/data/validator/RangeValidator.java
@@ -0,0 +1,186 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.data.validator;
+
+/**
+ * An base implementation for validating any objects that implement
+ * {@link Comparable}.
+ *
+ * Verifies that the value is of the given type and within the (optionally)
+ * given limits. Typically you want to use a sub class of this like
+ * {@link IntegerRangeValidator}, {@link DoubleRangeValidator} or
+ * {@link DateRangeValidator} in applications.
+ * <p>
+ * Note that {@link RangeValidator} always accept null values. Make a field
+ * required to ensure that no empty values are accepted or override
+ * {@link #isValidValue(Comparable)}.
+ * </p>
+ *
+ * @param <T>
+ * The type of Number to validate. Must implement Comparable so that
+ * minimum and maximum checks work.
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class RangeValidator<T extends Comparable> extends AbstractValidator<T> {
+
+ private T minValue = null;
+ private boolean minValueIncluded = true;
+ private T maxValue = null;
+ private boolean maxValueIncluded = true;
+ private Class<T> type;
+
+ /**
+ * Creates a new range validator of the given type.
+ *
+ * @param errorMessage
+ * The error message to use if validation fails
+ * @param type
+ * The type of object the validator can validate.
+ * @param minValue
+ * The minimum value that should be accepted or null for no limit
+ * @param maxValue
+ * The maximum value that should be accepted or null for no limit
+ */
+ public RangeValidator(String errorMessage, Class<T> type, T minValue,
+ T maxValue) {
+ super(errorMessage);
+ this.type = type;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ /**
+ * Checks if the minimum value is part of the accepted range
+ *
+ * @return true if the minimum value is part of the range, false otherwise
+ */
+ public boolean isMinValueIncluded() {
+ return minValueIncluded;
+ }
+
+ /**
+ * Sets if the minimum value is part of the accepted range
+ *
+ * @param minValueIncluded
+ * true if the minimum value should be part of the range, false
+ * otherwise
+ */
+ public void setMinValueIncluded(boolean minValueIncluded) {
+ this.minValueIncluded = minValueIncluded;
+ }
+
+ /**
+ * Checks if the maximum value is part of the accepted range
+ *
+ * @return true if the maximum value is part of the range, false otherwise
+ */
+ public boolean isMaxValueIncluded() {
+ return maxValueIncluded;
+ }
+
+ /**
+ * Sets if the maximum value is part of the accepted range
+ *
+ * @param maxValueIncluded
+ * true if the maximum value should be part of the range, false
+ * otherwise
+ */
+ public void setMaxValueIncluded(boolean maxValueIncluded) {
+ this.maxValueIncluded = maxValueIncluded;
+ }
+
+ /**
+ * Gets the minimum value of the range
+ *
+ * @return the minimum value
+ */
+ public T getMinValue() {
+ return minValue;
+ }
+
+ /**
+ * Sets the minimum value of the range. Use
+ * {@link #setMinValueIncluded(boolean)} to control whether this value is
+ * part of the range or not.
+ *
+ * @param minValue
+ * the minimum value
+ */
+ public void setMinValue(T minValue) {
+ this.minValue = minValue;
+ }
+
+ /**
+ * Gets the maximum value of the range
+ *
+ * @return the maximum value
+ */
+ public T getMaxValue() {
+ return maxValue;
+ }
+
+ /**
+ * Sets the maximum value of the range. Use
+ * {@link #setMaxValueIncluded(boolean)} to control whether this value is
+ * part of the range or not.
+ *
+ * @param maxValue
+ * the maximum value
+ */
+ public void setMaxValue(T maxValue) {
+ this.maxValue = maxValue;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object
+ * )
+ */
+ @Override
+ protected boolean isValidValue(T value) {
+ if (value == null) {
+ return true;
+ }
+
+ if (getMinValue() != null) {
+ // Ensure that the min limit is ok
+ int result = value.compareTo(getMinValue());
+ if (result < 0) {
+ // value less than min value
+ return false;
+ } else if (result == 0 && !isMinValueIncluded()) {
+ // values equal and min value not included
+ return false;
+ }
+ }
+ if (getMaxValue() != null) {
+ // Ensure that the Max limit is ok
+ int result = value.compareTo(getMaxValue());
+ if (result > 0) {
+ // value greater than max value
+ return false;
+ } else if (result == 0 && !isMaxValueIncluded()) {
+ // values equal and max value not included
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.validator.AbstractValidator#getType()
+ */
+ @Override
+ public Class<T> getType() {
+ return type;
+ }
+
+}
diff --git a/src/com/vaadin/data/validator/RegexpValidator.java b/src/com/vaadin/data/validator/RegexpValidator.java
index 684de7697c..dec0bf0be9 100644
--- a/src/com/vaadin/data/validator/RegexpValidator.java
+++ b/src/com/vaadin/data/validator/RegexpValidator.java
@@ -62,8 +62,11 @@ public class RegexpValidator extends AbstractStringValidator {
this.complete = complete;
}
+ /* (non-Javadoc)
+ * @see com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object)
+ */
@Override
- protected boolean isValidString(String value) {
+ protected boolean isValidValue(String value) {
if (complete) {
return getMatcher(value).matches();
} else {
diff --git a/src/com/vaadin/data/validator/StringLengthValidator.java b/src/com/vaadin/data/validator/StringLengthValidator.java
index d7edea216d..54b2d28f58 100644
--- a/src/com/vaadin/data/validator/StringLengthValidator.java
+++ b/src/com/vaadin/data/validator/StringLengthValidator.java
@@ -14,11 +14,11 @@ package com.vaadin.data.validator;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class StringLengthValidator extends AbstractValidator {
+public class StringLengthValidator extends AbstractStringValidator {
- private int minLength = -1;
+ private Integer minLength = null;
- private int maxLength = -1;
+ private Integer maxLength = null;
private boolean allowNull = true;
@@ -33,21 +33,25 @@ public class StringLengthValidator extends AbstractValidator {
}
/**
- * Creates a new StringLengthValidator with a given error message,
- * permissable lengths and null-string allowance.
+ * Creates a new StringLengthValidator with a given error message and
+ * minimum and maximum length limits.
*
* @param errorMessage
* the message to display in case the value does not validate.
* @param minLength
- * the minimum permissible length of the string.
+ * the minimum permissible length of the string or null for no
+ * limit. A negative value for no limit is also supported for
+ * backwards compatibility.
* @param maxLength
- * the maximum permissible length of the string.
+ * the maximum permissible length of the string or null for no
+ * limit. A negative value for no limit is also supported for
+ * backwards compatibility.
* @param allowNull
* Are null strings permissible? This can be handled better by
* setting a field as required or not.
*/
- public StringLengthValidator(String errorMessage, int minLength,
- int maxLength, boolean allowNull) {
+ public StringLengthValidator(String errorMessage, Integer minLength,
+ Integer maxLength, boolean allowNull) {
this(errorMessage);
setMinLength(minLength);
setMaxLength(maxLength);
@@ -61,17 +65,14 @@ public class StringLengthValidator extends AbstractValidator {
* the value to validate.
* @return <code>true</code> for valid value, otherwise <code>false</code>.
*/
- public boolean isValid(Object value) {
+ @Override
+ protected boolean isValidValue(String value) {
if (value == null) {
return allowNull;
}
- final String s = value.toString();
- if (s == null) {
- return allowNull;
- }
- final int len = s.length();
- if ((minLength >= 0 && len < minLength)
- || (maxLength >= 0 && len > maxLength)) {
+ final int len = value.length();
+ if ((minLength != null && minLength > -1 && len < minLength)
+ || (maxLength != null && maxLength > -1 && len > maxLength)) {
return false;
}
return true;
@@ -91,18 +92,18 @@ public class StringLengthValidator extends AbstractValidator {
/**
* Gets the maximum permissible length of the string.
*
- * @return the maximum length of the string.
+ * @return the maximum length of the string or null if there is no limit
*/
- public final int getMaxLength() {
+ public Integer getMaxLength() {
return maxLength;
}
/**
* Gets the minimum permissible length of the string.
*
- * @return the minimum length of the string.
+ * @return the minimum length of the string or null if there is no limit
*/
- public final int getMinLength() {
+ public Integer getMinLength() {
return minLength;
}
@@ -119,12 +120,9 @@ public class StringLengthValidator extends AbstractValidator {
* Sets the maximum permissible length of the string.
*
* @param maxLength
- * the length to set.
+ * the maximum length to accept or null for no limit
*/
- public void setMaxLength(int maxLength) {
- if (maxLength < -1) {
- maxLength = -1;
- }
+ public void setMaxLength(Integer maxLength) {
this.maxLength = maxLength;
}
@@ -132,12 +130,9 @@ public class StringLengthValidator extends AbstractValidator {
* Sets the minimum permissible length.
*
* @param minLength
- * the length to set.
+ * the minimum length to accept or null for no limit
*/
- public void setMinLength(int minLength) {
- if (minLength < -1) {
- minLength = -1;
- }
+ public void setMinLength(Integer minLength) {
this.minLength = minLength;
}
diff --git a/src/com/vaadin/external/json/JSONArray.java b/src/com/vaadin/external/json/JSONArray.java
new file mode 100644
index 0000000000..2307749ffc
--- /dev/null
+++ b/src/com/vaadin/external/json/JSONArray.java
@@ -0,0 +1,963 @@
+package com.vaadin.external.json;
+
+/*
+ Copyright (c) 2002 JSON.org
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ The Software shall be used for Good, not Evil.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A JSONArray is an ordered sequence of values. Its external text form is a
+ * string wrapped in square brackets with commas separating the values. The
+ * internal form is an object having <code>get</code> and <code>opt</code>
+ * methods for accessing the values by index, and <code>put</code> methods for
+ * adding or replacing values. The values can be any of these types:
+ * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
+ * <code>Number</code>, <code>String</code>, or the
+ * <code>JSONObject.NULL object</code>.
+ * <p>
+ * The constructor can convert a JSON text into a Java object. The
+ * <code>toString</code> method converts to JSON text.
+ * <p>
+ * A <code>get</code> method returns a value if one can be found, and throws an
+ * exception if one cannot be found. An <code>opt</code> method returns a
+ * default value instead of throwing an exception, and so is useful for
+ * obtaining optional values.
+ * <p>
+ * The generic <code>get()</code> and <code>opt()</code> methods return an
+ * object which you can cast or query for type. There are also typed
+ * <code>get</code> and <code>opt</code> methods that do type checking and type
+ * coercion for you.
+ * <p>
+ * The texts produced by the <code>toString</code> methods strictly conform to
+ * JSON syntax rules. The constructors are more forgiving in the texts they will
+ * accept:
+ * <ul>
+ * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
+ * before the closing bracket.</li>
+ * <li>The <code>null</code> value will be inserted when there is <code>,</code>
+ * &nbsp;<small>(comma)</small> elision.</li>
+ * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
+ * quote)</small>.</li>
+ * <li>Strings do not need to be quoted at all if they do not begin with a quote
+ * or single quote, and if they do not contain leading or trailing spaces, and
+ * if they do not contain any of these characters:
+ * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
+ * if they are not the reserved words <code>true</code>, <code>false</code>, or
+ * <code>null</code>.</li>
+ * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
+ * well as by <code>,</code> <small>(comma)</small>.</li>
+ * <li>Numbers may have the <code>0x-</code> <small>(hex)</small> prefix.</li>
+ * </ul>
+ *
+ * @author JSON.org
+ * @version 2011-08-25
+ */
+public class JSONArray implements Serializable {
+
+ /**
+ * The arrayList where the JSONArray's properties are kept.
+ */
+ private ArrayList myArrayList;
+
+ /**
+ * Construct an empty JSONArray.
+ */
+ public JSONArray() {
+ myArrayList = new ArrayList();
+ }
+
+ /**
+ * Construct a JSONArray from a JSONTokener.
+ *
+ * @param x
+ * A JSONTokener
+ * @throws JSONException
+ * If there is a syntax error.
+ */
+ public JSONArray(JSONTokener x) throws JSONException {
+ this();
+ if (x.nextClean() != '[') {
+ throw x.syntaxError("A JSONArray text must start with '['");
+ }
+ if (x.nextClean() != ']') {
+ x.back();
+ for (;;) {
+ if (x.nextClean() == ',') {
+ x.back();
+ myArrayList.add(JSONObject.NULL);
+ } else {
+ x.back();
+ myArrayList.add(x.nextValue());
+ }
+ switch (x.nextClean()) {
+ case ';':
+ case ',':
+ if (x.nextClean() == ']') {
+ return;
+ }
+ x.back();
+ break;
+ case ']':
+ return;
+ default:
+ throw x.syntaxError("Expected a ',' or ']'");
+ }
+ }
+ }
+ }
+
+ /**
+ * Construct a JSONArray from a source JSON text.
+ *
+ * @param source
+ * A string that begins with <code>[</code>&nbsp;<small>(left
+ * bracket)</small> and ends with <code>]</code>
+ * &nbsp;<small>(right bracket)</small>.
+ * @throws JSONException
+ * If there is a syntax error.
+ */
+ public JSONArray(String source) throws JSONException {
+ this(new JSONTokener(source));
+ }
+
+ /**
+ * Construct a JSONArray from a Collection.
+ *
+ * @param collection
+ * A Collection.
+ */
+ public JSONArray(Collection collection) {
+ myArrayList = new ArrayList();
+ if (collection != null) {
+ Iterator iter = collection.iterator();
+ while (iter.hasNext()) {
+ myArrayList.add(JSONObject.wrap(iter.next()));
+ }
+ }
+ }
+
+ /**
+ * Construct a JSONArray from an array
+ *
+ * @throws JSONException
+ * If not an array.
+ */
+ public JSONArray(Object array) throws JSONException {
+ this();
+ if (array.getClass().isArray()) {
+ int length = Array.getLength(array);
+ for (int i = 0; i < length; i += 1) {
+ this.put(JSONObject.wrap(Array.get(array, i)));
+ }
+ } else {
+ throw new JSONException(
+ "JSONArray initial value should be a string or collection or array.");
+ }
+ }
+
+ /**
+ * Get the object value associated with an index.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return An object value.
+ * @throws JSONException
+ * If there is no value for the index.
+ */
+ public Object get(int index) throws JSONException {
+ Object object = opt(index);
+ if (object == null) {
+ throw new JSONException("JSONArray[" + index + "] not found.");
+ }
+ return object;
+ }
+
+ /**
+ * Get the boolean value associated with an index. The string values "true"
+ * and "false" are converted to boolean.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The truth.
+ * @throws JSONException
+ * If there is no value for the index or if the value is not
+ * convertible to boolean.
+ */
+ public boolean getBoolean(int index) throws JSONException {
+ Object object = get(index);
+ if (object.equals(Boolean.FALSE)
+ || (object instanceof String && ((String) object)
+ .equalsIgnoreCase("false"))) {
+ return false;
+ } else if (object.equals(Boolean.TRUE)
+ || (object instanceof String && ((String) object)
+ .equalsIgnoreCase("true"))) {
+ return true;
+ }
+ throw new JSONException("JSONArray[" + index + "] is not a boolean.");
+ }
+
+ /**
+ * Get the double value associated with an index.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException
+ * If the key is not found or if the value cannot be converted
+ * to a number.
+ */
+ public double getDouble(int index) throws JSONException {
+ Object object = get(index);
+ try {
+ return object instanceof Number ? ((Number) object).doubleValue()
+ : Double.parseDouble((String) object);
+ } catch (Exception e) {
+ throw new JSONException("JSONArray[" + index + "] is not a number.");
+ }
+ }
+
+ /**
+ * Get the int value associated with an index.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException
+ * If the key is not found or if the value is not a number.
+ */
+ public int getInt(int index) throws JSONException {
+ Object object = get(index);
+ try {
+ return object instanceof Number ? ((Number) object).intValue()
+ : Integer.parseInt((String) object);
+ } catch (Exception e) {
+ throw new JSONException("JSONArray[" + index + "] is not a number.");
+ }
+ }
+
+ /**
+ * Get the JSONArray associated with an index.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return A JSONArray value.
+ * @throws JSONException
+ * If there is no value for the index. or if the value is not a
+ * JSONArray
+ */
+ public JSONArray getJSONArray(int index) throws JSONException {
+ Object object = get(index);
+ if (object instanceof JSONArray) {
+ return (JSONArray) object;
+ }
+ throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
+ }
+
+ /**
+ * Get the JSONObject associated with an index.
+ *
+ * @param index
+ * subscript
+ * @return A JSONObject value.
+ * @throws JSONException
+ * If there is no value for the index or if the value is not a
+ * JSONObject
+ */
+ public JSONObject getJSONObject(int index) throws JSONException {
+ Object object = get(index);
+ if (object instanceof JSONObject) {
+ return (JSONObject) object;
+ }
+ throw new JSONException("JSONArray[" + index + "] is not a JSONObject.");
+ }
+
+ /**
+ * Get the long value associated with an index.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The value.
+ * @throws JSONException
+ * If the key is not found or if the value cannot be converted
+ * to a number.
+ */
+ public long getLong(int index) throws JSONException {
+ Object object = get(index);
+ try {
+ return object instanceof Number ? ((Number) object).longValue()
+ : Long.parseLong((String) object);
+ } catch (Exception e) {
+ throw new JSONException("JSONArray[" + index + "] is not a number.");
+ }
+ }
+
+ /**
+ * Get the string associated with an index.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return A string value.
+ * @throws JSONException
+ * If there is no string value for the index.
+ */
+ public String getString(int index) throws JSONException {
+ Object object = get(index);
+ if (object instanceof String) {
+ return (String) object;
+ }
+ throw new JSONException("JSONArray[" + index + "] not a string.");
+ }
+
+ /**
+ * Determine if the value is null.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return true if the value at the index is null, or if there is no value.
+ */
+ public boolean isNull(int index) {
+ return JSONObject.NULL.equals(opt(index));
+ }
+
+ /**
+ * Make a string from the contents of this JSONArray. The
+ * <code>separator</code> string is inserted between each element. Warning:
+ * This method assumes that the data structure is acyclical.
+ *
+ * @param separator
+ * A string that will be inserted between the elements.
+ * @return a string.
+ * @throws JSONException
+ * If the array contains an invalid number.
+ */
+ public String join(String separator) throws JSONException {
+ int len = length();
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < len; i += 1) {
+ if (i > 0) {
+ sb.append(separator);
+ }
+ sb.append(JSONObject.valueToString(myArrayList.get(i)));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get the number of elements in the JSONArray, included nulls.
+ *
+ * @return The length (or size).
+ */
+ public int length() {
+ return myArrayList.size();
+ }
+
+ /**
+ * Get the optional object value associated with an index.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return An object value, or null if there is no object at that index.
+ */
+ public Object opt(int index) {
+ return (index < 0 || index >= length()) ? null : myArrayList.get(index);
+ }
+
+ /**
+ * Get the optional boolean value associated with an index. It returns false
+ * if there is no value at that index, or if the value is not Boolean.TRUE
+ * or the String "true".
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The truth.
+ */
+ public boolean optBoolean(int index) {
+ return optBoolean(index, false);
+ }
+
+ /**
+ * Get the optional boolean value associated with an index. It returns the
+ * defaultValue if there is no value at that index or if it is not a Boolean
+ * or the String "true" or "false" (case insensitive).
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @param defaultValue
+ * A boolean default.
+ * @return The truth.
+ */
+ public boolean optBoolean(int index, boolean defaultValue) {
+ try {
+ return getBoolean(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get the optional double value associated with an index. NaN is returned
+ * if there is no value for the index, or if the value is not a number and
+ * cannot be converted to a number.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public double optDouble(int index) {
+ return optDouble(index, Double.NaN);
+ }
+
+ /**
+ * Get the optional double value associated with an index. The defaultValue
+ * is returned if there is no value for the index, or if the value is not a
+ * number and cannot be converted to a number.
+ *
+ * @param index
+ * subscript
+ * @param defaultValue
+ * The default value.
+ * @return The value.
+ */
+ public double optDouble(int index, double defaultValue) {
+ try {
+ return getDouble(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get the optional int value associated with an index. Zero is returned if
+ * there is no value for the index, or if the value is not a number and
+ * cannot be converted to a number.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public int optInt(int index) {
+ return optInt(index, 0);
+ }
+
+ /**
+ * Get the optional int value associated with an index. The defaultValue is
+ * returned if there is no value for the index, or if the value is not a
+ * number and cannot be converted to a number.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @param defaultValue
+ * The default value.
+ * @return The value.
+ */
+ public int optInt(int index, int defaultValue) {
+ try {
+ return getInt(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get the optional JSONArray associated with an index.
+ *
+ * @param index
+ * subscript
+ * @return A JSONArray value, or null if the index has no value, or if the
+ * value is not a JSONArray.
+ */
+ public JSONArray optJSONArray(int index) {
+ Object o = opt(index);
+ return o instanceof JSONArray ? (JSONArray) o : null;
+ }
+
+ /**
+ * Get the optional JSONObject associated with an index. Null is returned if
+ * the key is not found, or null if the index has no value, or if the value
+ * is not a JSONObject.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return A JSONObject value.
+ */
+ public JSONObject optJSONObject(int index) {
+ Object o = opt(index);
+ return o instanceof JSONObject ? (JSONObject) o : null;
+ }
+
+ /**
+ * Get the optional long value associated with an index. Zero is returned if
+ * there is no value for the index, or if the value is not a number and
+ * cannot be converted to a number.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return The value.
+ */
+ public long optLong(int index) {
+ return optLong(index, 0);
+ }
+
+ /**
+ * Get the optional long value associated with an index. The defaultValue is
+ * returned if there is no value for the index, or if the value is not a
+ * number and cannot be converted to a number.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @param defaultValue
+ * The default value.
+ * @return The value.
+ */
+ public long optLong(int index, long defaultValue) {
+ try {
+ return getLong(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get the optional string value associated with an index. It returns an
+ * empty string if there is no value at that index. If the value is not a
+ * string and is not null, then it is coverted to a string.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @return A String value.
+ */
+ public String optString(int index) {
+ return optString(index, "");
+ }
+
+ /**
+ * Get the optional string associated with an index. The defaultValue is
+ * returned if the key is not found.
+ *
+ * @param index
+ * The index must be between 0 and length() - 1.
+ * @param defaultValue
+ * The default value.
+ * @return A String value.
+ */
+ public String optString(int index, String defaultValue) {
+ Object object = opt(index);
+ return JSONObject.NULL.equals(object) ? object.toString()
+ : defaultValue;
+ }
+
+ /**
+ * Append a boolean value. This increases the array's length by one.
+ *
+ * @param value
+ * A boolean value.
+ * @return this.
+ */
+ public JSONArray put(boolean value) {
+ put(value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+ /**
+ * Put a value in the JSONArray, where the value will be a JSONArray which
+ * is produced from a Collection.
+ *
+ * @param value
+ * A Collection value.
+ * @return this.
+ */
+ public JSONArray put(Collection value) {
+ put(new JSONArray(value));
+ return this;
+ }
+
+ /**
+ * Append a double value. This increases the array's length by one.
+ *
+ * @param value
+ * A double value.
+ * @throws JSONException
+ * if the value is not finite.
+ * @return this.
+ */
+ public JSONArray put(double value) throws JSONException {
+ Double d = new Double(value);
+ JSONObject.testValidity(d);
+ put(d);
+ return this;
+ }
+
+ /**
+ * Append an int value. This increases the array's length by one.
+ *
+ * @param value
+ * An int value.
+ * @return this.
+ */
+ public JSONArray put(int value) {
+ put(new Integer(value));
+ return this;
+ }
+
+ /**
+ * Append an long value. This increases the array's length by one.
+ *
+ * @param value
+ * A long value.
+ * @return this.
+ */
+ public JSONArray put(long value) {
+ put(new Long(value));
+ return this;
+ }
+
+ /**
+ * Put a value in the JSONArray, where the value will be a JSONObject which
+ * is produced from a Map.
+ *
+ * @param value
+ * A Map value.
+ * @return this.
+ */
+ public JSONArray put(Map value) {
+ put(new JSONObject(value));
+ return this;
+ }
+
+ /**
+ * Append an object value. This increases the array's length by one.
+ *
+ * @param value
+ * An object value. The value should be a Boolean, Double,
+ * Integer, JSONArray, JSONObject, Long, or String, or the
+ * JSONObject.NULL object.
+ * @return this.
+ */
+ public JSONArray put(Object value) {
+ myArrayList.add(value);
+ return this;
+ }
+
+ /**
+ * Put or replace a boolean value in the JSONArray. If the index is greater
+ * than the length of the JSONArray, then null elements will be added as
+ * necessary to pad it out.
+ *
+ * @param index
+ * The subscript.
+ * @param value
+ * A boolean value.
+ * @return this.
+ * @throws JSONException
+ * If the index is negative.
+ */
+ public JSONArray put(int index, boolean value) throws JSONException {
+ put(index, value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+ /**
+ * Put a value in the JSONArray, where the value will be a JSONArray which
+ * is produced from a Collection.
+ *
+ * @param index
+ * The subscript.
+ * @param value
+ * A Collection value.
+ * @return this.
+ * @throws JSONException
+ * If the index is negative or if the value is not finite.
+ */
+ public JSONArray put(int index, Collection value) throws JSONException {
+ put(index, new JSONArray(value));
+ return this;
+ }
+
+ /**
+ * Put or replace a double value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad it
+ * out.
+ *
+ * @param index
+ * The subscript.
+ * @param value
+ * A double value.
+ * @return this.
+ * @throws JSONException
+ * If the index is negative or if the value is not finite.
+ */
+ public JSONArray put(int index, double value) throws JSONException {
+ put(index, new Double(value));
+ return this;
+ }
+
+ /**
+ * Put or replace an int value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad it
+ * out.
+ *
+ * @param index
+ * The subscript.
+ * @param value
+ * An int value.
+ * @return this.
+ * @throws JSONException
+ * If the index is negative.
+ */
+ public JSONArray put(int index, int value) throws JSONException {
+ put(index, new Integer(value));
+ return this;
+ }
+
+ /**
+ * Put or replace a long value. If the index is greater than the length of
+ * the JSONArray, then null elements will be added as necessary to pad it
+ * out.
+ *
+ * @param index
+ * The subscript.
+ * @param value
+ * A long value.
+ * @return this.
+ * @throws JSONException
+ * If the index is negative.
+ */
+ public JSONArray put(int index, long value) throws JSONException {
+ put(index, new Long(value));
+ return this;
+ }
+
+ /**
+ * Put a value in the JSONArray, where the value will be a JSONObject that
+ * is produced from a Map.
+ *
+ * @param index
+ * The subscript.
+ * @param value
+ * The Map value.
+ * @return this.
+ * @throws JSONException
+ * If the index is negative or if the the value is an invalid
+ * number.
+ */
+ public JSONArray put(int index, Map value) throws JSONException {
+ put(index, new JSONObject(value));
+ return this;
+ }
+
+ /**
+ * Put or replace an object value in the JSONArray. If the index is greater
+ * than the length of the JSONArray, then null elements will be added as
+ * necessary to pad it out.
+ *
+ * @param index
+ * The subscript.
+ * @param value
+ * The value to put into the array. The value should be a
+ * Boolean, Double, Integer, JSONArray, JSONObject, Long, or
+ * String, or the JSONObject.NULL object.
+ * @return this.
+ * @throws JSONException
+ * If the index is negative or if the the value is an invalid
+ * number.
+ */
+ public JSONArray put(int index, Object value) throws JSONException {
+ JSONObject.testValidity(value);
+ if (index < 0) {
+ throw new JSONException("JSONArray[" + index + "] not found.");
+ }
+ if (index < length()) {
+ myArrayList.set(index, value);
+ } else {
+ while (index != length()) {
+ put(JSONObject.NULL);
+ }
+ put(value);
+ }
+ return this;
+ }
+
+ /**
+ * Remove an index and close the hole.
+ *
+ * @param index
+ * The index of the element to be removed.
+ * @return The value that was associated with the index, or null if there
+ * was no value.
+ */
+ public Object remove(int index) {
+ Object o = opt(index);
+ myArrayList.remove(index);
+ return o;
+ }
+
+ /**
+ * Produce a JSONObject by combining a JSONArray of names with the values of
+ * this JSONArray.
+ *
+ * @param names
+ * A JSONArray containing a list of key strings. These will be
+ * paired with the values.
+ * @return A JSONObject, or null if there are no names or if this JSONArray
+ * has no values.
+ * @throws JSONException
+ * If any of the names are null.
+ */
+ public JSONObject toJSONObject(JSONArray names) throws JSONException {
+ if (names == null || names.length() == 0 || length() == 0) {
+ return null;
+ }
+ JSONObject jo = new JSONObject();
+ for (int i = 0; i < names.length(); i += 1) {
+ jo.put(names.getString(i), opt(i));
+ }
+ return jo;
+ }
+
+ /**
+ * Make a JSON text of this JSONArray. For compactness, no unnecessary
+ * whitespace is added. If it is not possible to produce a syntactically
+ * correct JSON text then null will be returned instead. This could occur if
+ * the array contains an invalid number.
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return a printable, displayable, transmittable representation of the
+ * array.
+ */
+ @Override
+ public String toString() {
+ try {
+ return '[' + join(",") + ']';
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Make a prettyprinted JSON text of this JSONArray. Warning: This method
+ * assumes that the data structure is acyclical.
+ *
+ * @param indentFactor
+ * The number of spaces to add to each level of indentation.
+ * @return a printable, displayable, transmittable representation of the
+ * object, beginning with <code>[</code>&nbsp;<small>(left
+ * bracket)</small> and ending with <code>]</code>
+ * &nbsp;<small>(right bracket)</small>.
+ * @throws JSONException
+ */
+ public String toString(int indentFactor) throws JSONException {
+ return toString(indentFactor, 0);
+ }
+
+ /**
+ * Make a prettyprinted JSON text of this JSONArray. Warning: This method
+ * assumes that the data structure is acyclical.
+ *
+ * @param indentFactor
+ * The number of spaces to add to each level of indentation.
+ * @param indent
+ * The indention of the top level.
+ * @return a printable, displayable, transmittable representation of the
+ * array.
+ * @throws JSONException
+ */
+ String toString(int indentFactor, int indent) throws JSONException {
+ int len = length();
+ if (len == 0) {
+ return "[]";
+ }
+ int i;
+ StringBuffer sb = new StringBuffer("[");
+ if (len == 1) {
+ sb.append(JSONObject.valueToString(myArrayList.get(0),
+ indentFactor, indent));
+ } else {
+ int newindent = indent + indentFactor;
+ sb.append('\n');
+ for (i = 0; i < len; i += 1) {
+ if (i > 0) {
+ sb.append(",\n");
+ }
+ for (int j = 0; j < newindent; j += 1) {
+ sb.append(' ');
+ }
+ sb.append(JSONObject.valueToString(myArrayList.get(i),
+ indentFactor, newindent));
+ }
+ sb.append('\n');
+ for (i = 0; i < indent; i += 1) {
+ sb.append(' ');
+ }
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ /**
+ * Write the contents of the JSONArray as JSON text to a writer. For
+ * compactness, no whitespace is added.
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return The writer.
+ * @throws JSONException
+ */
+ public Writer write(Writer writer) throws JSONException {
+ try {
+ boolean b = false;
+ int len = length();
+
+ writer.write('[');
+
+ for (int i = 0; i < len; i += 1) {
+ if (b) {
+ writer.write(',');
+ }
+ Object v = myArrayList.get(i);
+ if (v instanceof JSONObject) {
+ ((JSONObject) v).write(writer);
+ } else if (v instanceof JSONArray) {
+ ((JSONArray) v).write(writer);
+ } else {
+ writer.write(JSONObject.valueToString(v));
+ }
+ b = true;
+ }
+ writer.write(']');
+ return writer;
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/external/json/JSONException.java b/src/com/vaadin/external/json/JSONException.java
new file mode 100644
index 0000000000..d799021506
--- /dev/null
+++ b/src/com/vaadin/external/json/JSONException.java
@@ -0,0 +1,28 @@
+package com.vaadin.external.json;
+
+/**
+ * The JSONException is thrown by the JSON.org classes when things are amiss.
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class JSONException extends Exception {
+ private static final long serialVersionUID = 0;
+ private Throwable cause;
+
+ /**
+ * Constructs a JSONException with an explanatory message.
+ * @param message Detail about the reason for the exception.
+ */
+ public JSONException(String message) {
+ super(message);
+ }
+
+ public JSONException(Throwable cause) {
+ super(cause.getMessage());
+ this.cause = cause;
+ }
+
+ public Throwable getCause() {
+ return this.cause;
+ }
+}
diff --git a/src/com/vaadin/external/json/JSONObject.java b/src/com/vaadin/external/json/JSONObject.java
new file mode 100644
index 0000000000..ba772933be
--- /dev/null
+++ b/src/com/vaadin/external/json/JSONObject.java
@@ -0,0 +1,1693 @@
+package com.vaadin.external.json;
+
+/*
+ Copyright (c) 2002 JSON.org
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ The Software shall be used for Good, not Evil.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * A JSONObject is an unordered collection of name/value pairs. Its external
+ * form is a string wrapped in curly braces with colons between the names and
+ * values, and commas between the values and names. The internal form is an
+ * object having <code>get</code> and <code>opt</code> methods for accessing the
+ * values by name, and <code>put</code> methods for adding or replacing values
+ * by name. The values can be any of these types: <code>Boolean</code>,
+ * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>,
+ * <code>String</code>, or the <code>JSONObject.NULL</code> object. A JSONObject
+ * constructor can be used to convert an external form JSON text into an
+ * internal form whose values can be retrieved with the <code>get</code> and
+ * <code>opt</code> methods, or to convert values into a JSON text using the
+ * <code>put</code> and <code>toString</code> methods. A <code>get</code> method
+ * returns a value if one can be found, and throws an exception if one cannot be
+ * found. An <code>opt</code> method returns a default value instead of throwing
+ * an exception, and so is useful for obtaining optional values.
+ * <p>
+ * The generic <code>get()</code> and <code>opt()</code> methods return an
+ * object, which you can cast or query for type. There are also typed
+ * <code>get</code> and <code>opt</code> methods that do type checking and type
+ * coercion for you. The opt methods differ from the get methods in that they do
+ * not throw. Instead, they return a specified value, such as null.
+ * <p>
+ * The <code>put</code> methods add or replace values in an object. For example,
+ *
+ * <pre>
+ * myString = new JSONObject().put(&quot;JSON&quot;, &quot;Hello, World!&quot;).toString();
+ * </pre>
+ *
+ * produces the string <code>{"JSON": "Hello, World"}</code>.
+ * <p>
+ * The texts produced by the <code>toString</code> methods strictly conform to
+ * the JSON syntax rules. The constructors are more forgiving in the texts they
+ * will accept:
+ * <ul>
+ * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
+ * before the closing brace.</li>
+ * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
+ * quote)</small>.</li>
+ * <li>Strings do not need to be quoted at all if they do not begin with a quote
+ * or single quote, and if they do not contain leading or trailing spaces, and
+ * if they do not contain any of these characters:
+ * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
+ * if they are not the reserved words <code>true</code>, <code>false</code>, or
+ * <code>null</code>.</li>
+ * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as by
+ * <code>:</code>.</li>
+ * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as
+ * well as by <code>,</code> <small>(comma)</small>.</li>
+ * <li>Numbers may have the <code>0x-</code> <small>(hex)</small> prefix.</li>
+ * </ul>
+ *
+ * @author JSON.org
+ * @version 2011-10-16
+ */
+public class JSONObject implements Serializable {
+
+ /**
+ * JSONObject.NULL is equivalent to the value that JavaScript calls null,
+ * whilst Java's null is equivalent to the value that JavaScript calls
+ * undefined.
+ */
+ private static final class Null implements Serializable {
+
+ /**
+ * There is only intended to be a single instance of the NULL object, so
+ * the clone method returns itself.
+ *
+ * @return NULL.
+ */
+ @Override
+ protected final Object clone() {
+ return this;
+ }
+
+ /**
+ * A Null object is equal to the null value and to itself.
+ *
+ * @param object
+ * An object to test for nullness.
+ * @return true if the object parameter is the JSONObject.NULL object or
+ * null.
+ */
+ @Override
+ public boolean equals(Object object) {
+ return object == null || object == this;
+ }
+
+ /**
+ * Get the "null" string value.
+ *
+ * @return The string "null".
+ */
+ @Override
+ public String toString() {
+ return "null";
+ }
+ }
+
+ /**
+ * The map where the JSONObject's properties are kept.
+ */
+ private Map map;
+
+ /**
+ * It is sometimes more convenient and less ambiguous to have a
+ * <code>NULL</code> object than to use Java's <code>null</code> value.
+ * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
+ * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
+ */
+ public static final Object NULL = new Null();
+
+ /**
+ * Construct an empty JSONObject.
+ */
+ public JSONObject() {
+ map = new HashMap();
+ }
+
+ /**
+ * Construct a JSONObject from a subset of another JSONObject. An array of
+ * strings is used to identify the keys that should be copied. Missing keys
+ * are ignored.
+ *
+ * @param jo
+ * A JSONObject.
+ * @param names
+ * An array of strings.
+ * @throws JSONException
+ * @exception JSONException
+ * If a value is a non-finite number or if a name is
+ * duplicated.
+ */
+ public JSONObject(JSONObject jo, String[] names) {
+ this();
+ for (int i = 0; i < names.length; i += 1) {
+ try {
+ putOnce(names[i], jo.opt(names[i]));
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ /**
+ * Construct a JSONObject from a JSONTokener.
+ *
+ * @param x
+ * A JSONTokener object containing the source string.
+ * @throws JSONException
+ * If there is a syntax error in the source string or a
+ * duplicated key.
+ */
+ public JSONObject(JSONTokener x) throws JSONException {
+ this();
+ char c;
+ String key;
+
+ if (x.nextClean() != '{') {
+ throw x.syntaxError("A JSONObject text must begin with '{'");
+ }
+ for (;;) {
+ c = x.nextClean();
+ switch (c) {
+ case 0:
+ throw x.syntaxError("A JSONObject text must end with '}'");
+ case '}':
+ return;
+ default:
+ x.back();
+ key = x.nextValue().toString();
+ }
+
+ // The key is followed by ':'. We will also tolerate '=' or '=>'.
+
+ c = x.nextClean();
+ if (c == '=') {
+ if (x.next() != '>') {
+ x.back();
+ }
+ } else if (c != ':') {
+ throw x.syntaxError("Expected a ':' after a key");
+ }
+ putOnce(key, x.nextValue());
+
+ // Pairs are separated by ','. We will also tolerate ';'.
+
+ switch (x.nextClean()) {
+ case ';':
+ case ',':
+ if (x.nextClean() == '}') {
+ return;
+ }
+ x.back();
+ break;
+ case '}':
+ return;
+ default:
+ throw x.syntaxError("Expected a ',' or '}'");
+ }
+ }
+ }
+
+ /**
+ * Construct a JSONObject from a Map.
+ *
+ * @param map
+ * A map object that can be used to initialize the contents of
+ * the JSONObject.
+ * @throws JSONException
+ */
+ public JSONObject(Map map) {
+ this.map = new HashMap();
+ if (map != null) {
+ Iterator i = map.entrySet().iterator();
+ while (i.hasNext()) {
+ Map.Entry e = (Map.Entry) i.next();
+ Object value = e.getValue();
+ if (value != null) {
+ this.map.put(e.getKey(), wrap(value));
+ }
+ }
+ }
+ }
+
+ /**
+ * Construct a JSONObject from an Object using bean getters. It reflects on
+ * all of the public methods of the object. For each of the methods with no
+ * parameters and a name starting with <code>"get"</code> or
+ * <code>"is"</code> followed by an uppercase letter, the method is invoked,
+ * and a key and the value returned from the getter method are put into the
+ * new JSONObject.
+ *
+ * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
+ * prefix. If the second remaining character is not upper case, then the
+ * first character is converted to lower case.
+ *
+ * For example, if an object has a method named <code>"getName"</code>, and
+ * if the result of calling <code>object.getName()</code> is
+ * <code>"Larry Fine"</code>, then the JSONObject will contain
+ * <code>"name": "Larry Fine"</code>.
+ *
+ * @param bean
+ * An object that has getter methods that should be used to make
+ * a JSONObject.
+ */
+ public JSONObject(Object bean) {
+ this();
+ populateMap(bean);
+ }
+
+ /**
+ * Construct a JSONObject from an Object, using reflection to find the
+ * public members. The resulting JSONObject's keys will be the strings from
+ * the names array, and the values will be the field values associated with
+ * those keys in the object. If a key is not found or not visible, then it
+ * will not be copied into the new JSONObject.
+ *
+ * @param object
+ * An object that has fields that should be used to make a
+ * JSONObject.
+ * @param names
+ * An array of strings, the names of the fields to be obtained
+ * from the object.
+ */
+ public JSONObject(Object object, String names[]) {
+ this();
+ Class c = object.getClass();
+ for (int i = 0; i < names.length; i += 1) {
+ String name = names[i];
+ try {
+ putOpt(name, c.getField(name).get(object));
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ /**
+ * Construct a JSONObject from a source JSON text string. This is the most
+ * commonly used JSONObject constructor.
+ *
+ * @param source
+ * A string beginning with <code>{</code>&nbsp;<small>(left
+ * brace)</small> and ending with <code>}</code>
+ * &nbsp;<small>(right brace)</small>.
+ * @exception JSONException
+ * If there is a syntax error in the source string or a
+ * duplicated key.
+ */
+ public JSONObject(String source) throws JSONException {
+ this(new JSONTokener(source));
+ }
+
+ /**
+ * Construct a JSONObject from a ResourceBundle.
+ *
+ * @param baseName
+ * The ResourceBundle base name.
+ * @param locale
+ * The Locale to load the ResourceBundle for.
+ * @throws JSONException
+ * If any JSONExceptions are detected.
+ */
+ public JSONObject(String baseName, Locale locale) throws JSONException {
+ this();
+ ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
+ Thread.currentThread().getContextClassLoader());
+
+ // Iterate through the keys in the bundle.
+
+ Enumeration keys = bundle.getKeys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ if (key instanceof String) {
+
+ // Go through the path, ensuring that there is a nested
+ // JSONObject for each
+ // segment except the last. Add the value using the last
+ // segment's name into
+ // the deepest nested JSONObject.
+
+ String[] path = ((String) key).split("\\.");
+ int last = path.length - 1;
+ JSONObject target = this;
+ for (int i = 0; i < last; i += 1) {
+ String segment = path[i];
+ JSONObject nextTarget = target.optJSONObject(segment);
+ if (nextTarget == null) {
+ nextTarget = new JSONObject();
+ target.put(segment, nextTarget);
+ }
+ target = nextTarget;
+ }
+ target.put(path[last], bundle.getString((String) key));
+ }
+ }
+ }
+
+ /**
+ * Accumulate values under a key. It is similar to the put method except
+ * that if there is already an object stored under the key then a JSONArray
+ * is stored under the key to hold all of the accumulated values. If there
+ * is already a JSONArray, then the new value is appended to it. In
+ * contrast, the put method replaces the previous value.
+ *
+ * If only one value is accumulated that is not a JSONArray, then the result
+ * will be the same as using put. But if multiple values are accumulated,
+ * then the result will be like append.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * An object to be accumulated under the key.
+ * @return this.
+ * @throws JSONException
+ * If the value is an invalid number or if the key is null.
+ */
+ public JSONObject accumulate(String key, Object value) throws JSONException {
+ testValidity(value);
+ Object object = opt(key);
+ if (object == null) {
+ put(key, value instanceof JSONArray ? new JSONArray().put(value)
+ : value);
+ } else if (object instanceof JSONArray) {
+ ((JSONArray) object).put(value);
+ } else {
+ put(key, new JSONArray().put(object).put(value));
+ }
+ return this;
+ }
+
+ /**
+ * Append values to the array under a key. If the key does not exist in the
+ * JSONObject, then the key is put in the JSONObject with its value being a
+ * JSONArray containing the value parameter. If the key was already
+ * associated with a JSONArray, then the value parameter is appended to it.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * An object to be accumulated under the key.
+ * @return this.
+ * @throws JSONException
+ * If the key is null or if the current value associated with
+ * the key is not a JSONArray.
+ */
+ public JSONObject append(String key, Object value) throws JSONException {
+ testValidity(value);
+ Object object = opt(key);
+ if (object == null) {
+ put(key, new JSONArray().put(value));
+ } else if (object instanceof JSONArray) {
+ put(key, ((JSONArray) object).put(value));
+ } else {
+ throw new JSONException("JSONObject[" + key
+ + "] is not a JSONArray.");
+ }
+ return this;
+ }
+
+ /**
+ * Produce a string from a double. The string "null" will be returned if the
+ * number is not finite.
+ *
+ * @param d
+ * A double.
+ * @return A String.
+ */
+ public static String doubleToString(double d) {
+ if (Double.isInfinite(d) || Double.isNaN(d)) {
+ return "null";
+ }
+
+ // Shave off trailing zeros and decimal point, if possible.
+
+ String string = Double.toString(d);
+ if (string.indexOf('.') > 0 && string.indexOf('e') < 0
+ && string.indexOf('E') < 0) {
+ while (string.endsWith("0")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ if (string.endsWith(".")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ }
+ return string;
+ }
+
+ /**
+ * Get the value object associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return The object associated with the key.
+ * @throws JSONException
+ * if the key is not found.
+ */
+ public Object get(String key) throws JSONException {
+ if (key == null) {
+ throw new JSONException("Null key.");
+ }
+ Object object = opt(key);
+ if (object == null) {
+ throw new JSONException("JSONObject[" + quote(key) + "] not found.");
+ }
+ return object;
+ }
+
+ /**
+ * Get the boolean value associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return The truth.
+ * @throws JSONException
+ * if the value is not a Boolean or the String "true" or
+ * "false".
+ */
+ public boolean getBoolean(String key) throws JSONException {
+ Object object = get(key);
+ if (object.equals(Boolean.FALSE)
+ || (object instanceof String && ((String) object)
+ .equalsIgnoreCase("false"))) {
+ return false;
+ } else if (object.equals(Boolean.TRUE)
+ || (object instanceof String && ((String) object)
+ .equalsIgnoreCase("true"))) {
+ return true;
+ }
+ throw new JSONException("JSONObject[" + quote(key)
+ + "] is not a Boolean.");
+ }
+
+ /**
+ * Get the double value associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return The numeric value.
+ * @throws JSONException
+ * if the key is not found or if the value is not a Number
+ * object and cannot be converted to a number.
+ */
+ public double getDouble(String key) throws JSONException {
+ Object object = get(key);
+ try {
+ return object instanceof Number ? ((Number) object).doubleValue()
+ : Double.parseDouble((String) object);
+ } catch (Exception e) {
+ throw new JSONException("JSONObject[" + quote(key)
+ + "] is not a number.");
+ }
+ }
+
+ /**
+ * Get the int value associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return The integer value.
+ * @throws JSONException
+ * if the key is not found or if the value cannot be converted
+ * to an integer.
+ */
+ public int getInt(String key) throws JSONException {
+ Object object = get(key);
+ try {
+ return object instanceof Number ? ((Number) object).intValue()
+ : Integer.parseInt((String) object);
+ } catch (Exception e) {
+ throw new JSONException("JSONObject[" + quote(key)
+ + "] is not an int.");
+ }
+ }
+
+ /**
+ * Get the JSONArray value associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return A JSONArray which is the value.
+ * @throws JSONException
+ * if the key is not found or if the value is not a JSONArray.
+ */
+ public JSONArray getJSONArray(String key) throws JSONException {
+ Object object = get(key);
+ if (object instanceof JSONArray) {
+ return (JSONArray) object;
+ }
+ throw new JSONException("JSONObject[" + quote(key)
+ + "] is not a JSONArray.");
+ }
+
+ /**
+ * Get the JSONObject value associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return A JSONObject which is the value.
+ * @throws JSONException
+ * if the key is not found or if the value is not a JSONObject.
+ */
+ public JSONObject getJSONObject(String key) throws JSONException {
+ Object object = get(key);
+ if (object instanceof JSONObject) {
+ return (JSONObject) object;
+ }
+ throw new JSONException("JSONObject[" + quote(key)
+ + "] is not a JSONObject.");
+ }
+
+ /**
+ * Get the long value associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return The long value.
+ * @throws JSONException
+ * if the key is not found or if the value cannot be converted
+ * to a long.
+ */
+ public long getLong(String key) throws JSONException {
+ Object object = get(key);
+ try {
+ return object instanceof Number ? ((Number) object).longValue()
+ : Long.parseLong((String) object);
+ } catch (Exception e) {
+ throw new JSONException("JSONObject[" + quote(key)
+ + "] is not a long.");
+ }
+ }
+
+ /**
+ * Get an array of field names from a JSONObject.
+ *
+ * @return An array of field names, or null if there are no names.
+ */
+ public static String[] getNames(JSONObject jo) {
+ int length = jo.length();
+ if (length == 0) {
+ return null;
+ }
+ Iterator iterator = jo.keys();
+ String[] names = new String[length];
+ int i = 0;
+ while (iterator.hasNext()) {
+ names[i] = (String) iterator.next();
+ i += 1;
+ }
+ return names;
+ }
+
+ /**
+ * Get an array of field names from an Object.
+ *
+ * @return An array of field names, or null if there are no names.
+ */
+ public static String[] getNames(Object object) {
+ if (object == null) {
+ return null;
+ }
+ Class klass = object.getClass();
+ Field[] fields = klass.getFields();
+ int length = fields.length;
+ if (length == 0) {
+ return null;
+ }
+ String[] names = new String[length];
+ for (int i = 0; i < length; i += 1) {
+ names[i] = fields[i].getName();
+ }
+ return names;
+ }
+
+ /**
+ * Get the string associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return A string which is the value.
+ * @throws JSONException
+ * if there is no string value for the key.
+ */
+ public String getString(String key) throws JSONException {
+ Object object = get(key);
+ if (object instanceof String) {
+ return (String) object;
+ }
+ throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
+ }
+
+ /**
+ * Determine if the JSONObject contains a specific key.
+ *
+ * @param key
+ * A key string.
+ * @return true if the key exists in the JSONObject.
+ */
+ public boolean has(String key) {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Increment a property of a JSONObject. If there is no such property,
+ * create one with a value of 1. If there is such a property, and if it is
+ * an Integer, Long, Double, or Float, then add one to it.
+ *
+ * @param key
+ * A key string.
+ * @return this.
+ * @throws JSONException
+ * If there is already a property with this name that is not an
+ * Integer, Long, Double, or Float.
+ */
+ public JSONObject increment(String key) throws JSONException {
+ Object value = opt(key);
+ if (value == null) {
+ put(key, 1);
+ } else if (value instanceof Integer) {
+ put(key, ((Integer) value).intValue() + 1);
+ } else if (value instanceof Long) {
+ put(key, ((Long) value).longValue() + 1);
+ } else if (value instanceof Double) {
+ put(key, ((Double) value).doubleValue() + 1);
+ } else if (value instanceof Float) {
+ put(key, ((Float) value).floatValue() + 1);
+ } else {
+ throw new JSONException("Unable to increment [" + quote(key) + "].");
+ }
+ return this;
+ }
+
+ /**
+ * Determine if the value associated with the key is null or if there is no
+ * value.
+ *
+ * @param key
+ * A key string.
+ * @return true if there is no value associated with the key or if the value
+ * is the JSONObject.NULL object.
+ */
+ public boolean isNull(String key) {
+ return JSONObject.NULL.equals(opt(key));
+ }
+
+ /**
+ * Get an enumeration of the keys of the JSONObject.
+ *
+ * @return An iterator of the keys.
+ */
+ public Iterator keys() {
+ return map.keySet().iterator();
+ }
+
+ /**
+ * Get the number of keys stored in the JSONObject.
+ *
+ * @return The number of keys in the JSONObject.
+ */
+ public int length() {
+ return map.size();
+ }
+
+ /**
+ * Produce a JSONArray containing the names of the elements of this
+ * JSONObject.
+ *
+ * @return A JSONArray containing the key strings, or null if the JSONObject
+ * is empty.
+ */
+ public JSONArray names() {
+ JSONArray ja = new JSONArray();
+ Iterator keys = keys();
+ while (keys.hasNext()) {
+ ja.put(keys.next());
+ }
+ return ja.length() == 0 ? null : ja;
+ }
+
+ /**
+ * Produce a string from a Number.
+ *
+ * @param number
+ * A Number
+ * @return A String.
+ * @throws JSONException
+ * If n is a non-finite number.
+ */
+ public static String numberToString(Number number) throws JSONException {
+ if (number == null) {
+ throw new JSONException("Null pointer");
+ }
+ testValidity(number);
+
+ // Shave off trailing zeros and decimal point, if possible.
+
+ String string = number.toString();
+ if (string.indexOf('.') > 0 && string.indexOf('e') < 0
+ && string.indexOf('E') < 0) {
+ while (string.endsWith("0")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ if (string.endsWith(".")) {
+ string = string.substring(0, string.length() - 1);
+ }
+ }
+ return string;
+ }
+
+ /**
+ * Get an optional value associated with a key.
+ *
+ * @param key
+ * A key string.
+ * @return An object which is the value, or null if there is no value.
+ */
+ public Object opt(String key) {
+ return key == null ? null : map.get(key);
+ }
+
+ /**
+ * Get an optional boolean associated with a key. It returns false if there
+ * is no such key, or if the value is not Boolean.TRUE or the String "true".
+ *
+ * @param key
+ * A key string.
+ * @return The truth.
+ */
+ public boolean optBoolean(String key) {
+ return optBoolean(key, false);
+ }
+
+ /**
+ * Get an optional boolean associated with a key. It returns the
+ * defaultValue if there is no such key, or if it is not a Boolean or the
+ * String "true" or "false" (case insensitive).
+ *
+ * @param key
+ * A key string.
+ * @param defaultValue
+ * The default.
+ * @return The truth.
+ */
+ public boolean optBoolean(String key, boolean defaultValue) {
+ try {
+ return getBoolean(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get an optional double associated with a key, or NaN if there is no such
+ * key or if its value is not a number. If the value is a string, an attempt
+ * will be made to evaluate it as a number.
+ *
+ * @param key
+ * A string which is the key.
+ * @return An object which is the value.
+ */
+ public double optDouble(String key) {
+ return optDouble(key, Double.NaN);
+ }
+
+ /**
+ * Get an optional double associated with a key, or the defaultValue if
+ * there is no such key or if its value is not a number. If the value is a
+ * string, an attempt will be made to evaluate it as a number.
+ *
+ * @param key
+ * A key string.
+ * @param defaultValue
+ * The default.
+ * @return An object which is the value.
+ */
+ public double optDouble(String key, double defaultValue) {
+ try {
+ return getDouble(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get an optional int value associated with a key, or zero if there is no
+ * such key or if the value is not a number. If the value is a string, an
+ * attempt will be made to evaluate it as a number.
+ *
+ * @param key
+ * A key string.
+ * @return An object which is the value.
+ */
+ public int optInt(String key) {
+ return optInt(key, 0);
+ }
+
+ /**
+ * Get an optional int value associated with a key, or the default if there
+ * is no such key or if the value is not a number. If the value is a string,
+ * an attempt will be made to evaluate it as a number.
+ *
+ * @param key
+ * A key string.
+ * @param defaultValue
+ * The default.
+ * @return An object which is the value.
+ */
+ public int optInt(String key, int defaultValue) {
+ try {
+ return getInt(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get an optional JSONArray associated with a key. It returns null if there
+ * is no such key, or if its value is not a JSONArray.
+ *
+ * @param key
+ * A key string.
+ * @return A JSONArray which is the value.
+ */
+ public JSONArray optJSONArray(String key) {
+ Object o = opt(key);
+ return o instanceof JSONArray ? (JSONArray) o : null;
+ }
+
+ /**
+ * Get an optional JSONObject associated with a key. It returns null if
+ * there is no such key, or if its value is not a JSONObject.
+ *
+ * @param key
+ * A key string.
+ * @return A JSONObject which is the value.
+ */
+ public JSONObject optJSONObject(String key) {
+ Object object = opt(key);
+ return object instanceof JSONObject ? (JSONObject) object : null;
+ }
+
+ /**
+ * Get an optional long value associated with a key, or zero if there is no
+ * such key or if the value is not a number. If the value is a string, an
+ * attempt will be made to evaluate it as a number.
+ *
+ * @param key
+ * A key string.
+ * @return An object which is the value.
+ */
+ public long optLong(String key) {
+ return optLong(key, 0);
+ }
+
+ /**
+ * Get an optional long value associated with a key, or the default if there
+ * is no such key or if the value is not a number. If the value is a string,
+ * an attempt will be made to evaluate it as a number.
+ *
+ * @param key
+ * A key string.
+ * @param defaultValue
+ * The default.
+ * @return An object which is the value.
+ */
+ public long optLong(String key, long defaultValue) {
+ try {
+ return getLong(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Get an optional string associated with a key. It returns an empty string
+ * if there is no such key. If the value is not a string and is not null,
+ * then it is converted to a string.
+ *
+ * @param key
+ * A key string.
+ * @return A string which is the value.
+ */
+ public String optString(String key) {
+ return optString(key, "");
+ }
+
+ /**
+ * Get an optional string associated with a key. It returns the defaultValue
+ * if there is no such key.
+ *
+ * @param key
+ * A key string.
+ * @param defaultValue
+ * The default.
+ * @return A string which is the value.
+ */
+ public String optString(String key, String defaultValue) {
+ Object object = opt(key);
+ return NULL.equals(object) ? defaultValue : object.toString();
+ }
+
+ private void populateMap(Object bean) {
+ Class klass = bean.getClass();
+
+ // If klass is a System class then set includeSuperClass to false.
+
+ boolean includeSuperClass = klass.getClassLoader() != null;
+
+ Method[] methods = (includeSuperClass) ? klass.getMethods() : klass
+ .getDeclaredMethods();
+ for (int i = 0; i < methods.length; i += 1) {
+ try {
+ Method method = methods[i];
+ if (Modifier.isPublic(method.getModifiers())) {
+ String name = method.getName();
+ String key = "";
+ if (name.startsWith("get")) {
+ if (name.equals("getClass")
+ || name.equals("getDeclaringClass")) {
+ key = "";
+ } else {
+ key = name.substring(3);
+ }
+ } else if (name.startsWith("is")) {
+ key = name.substring(2);
+ }
+ if (key.length() > 0
+ && Character.isUpperCase(key.charAt(0))
+ && method.getParameterTypes().length == 0) {
+ if (key.length() == 1) {
+ key = key.toLowerCase();
+ } else if (!Character.isUpperCase(key.charAt(1))) {
+ key = key.substring(0, 1).toLowerCase()
+ + key.substring(1);
+ }
+
+ Object result = method.invoke(bean, (Object[]) null);
+ if (result != null) {
+ map.put(key, wrap(result));
+ }
+ }
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ /**
+ * Put a key/boolean pair in the JSONObject.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * A boolean which is the value.
+ * @return this.
+ * @throws JSONException
+ * If the key is null.
+ */
+ public JSONObject put(String key, boolean value) throws JSONException {
+ put(key, value ? Boolean.TRUE : Boolean.FALSE);
+ return this;
+ }
+
+ /**
+ * Put a key/value pair in the JSONObject, where the value will be a
+ * JSONArray which is produced from a Collection.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * A Collection value.
+ * @return this.
+ * @throws JSONException
+ */
+ public JSONObject put(String key, Collection value) throws JSONException {
+ put(key, new JSONArray(value));
+ return this;
+ }
+
+ /**
+ * Put a key/double pair in the JSONObject.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * A double which is the value.
+ * @return this.
+ * @throws JSONException
+ * If the key is null or if the number is invalid.
+ */
+ public JSONObject put(String key, double value) throws JSONException {
+ put(key, new Double(value));
+ return this;
+ }
+
+ /**
+ * Put a key/int pair in the JSONObject.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * An int which is the value.
+ * @return this.
+ * @throws JSONException
+ * If the key is null.
+ */
+ public JSONObject put(String key, int value) throws JSONException {
+ put(key, new Integer(value));
+ return this;
+ }
+
+ /**
+ * Put a key/long pair in the JSONObject.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * A long which is the value.
+ * @return this.
+ * @throws JSONException
+ * If the key is null.
+ */
+ public JSONObject put(String key, long value) throws JSONException {
+ put(key, new Long(value));
+ return this;
+ }
+
+ /**
+ * Put a key/value pair in the JSONObject, where the value will be a
+ * JSONObject which is produced from a Map.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * A Map value.
+ * @return this.
+ * @throws JSONException
+ */
+ public JSONObject put(String key, Map value) throws JSONException {
+ put(key, new JSONObject(value));
+ return this;
+ }
+
+ /**
+ * Put a key/value pair in the JSONObject. If the value is null, then the
+ * key will be removed from the JSONObject if it is present.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * An object which is the value. It should be of one of these
+ * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
+ * String, or the JSONObject.NULL object.
+ * @return this.
+ * @throws JSONException
+ * If the value is non-finite number or if the key is null.
+ */
+ public JSONObject put(String key, Object value) throws JSONException {
+ if (key == null) {
+ throw new JSONException("Null key.");
+ }
+ if (value != null) {
+ testValidity(value);
+ map.put(key, value);
+ } else {
+ remove(key);
+ }
+ return this;
+ }
+
+ /**
+ * Put a key/value pair in the JSONObject, but only if the key and the value
+ * are both non-null, and only if there is not already a member with that
+ * name.
+ *
+ * @param key
+ * @param value
+ * @return his.
+ * @throws JSONException
+ * if the key is a duplicate
+ */
+ public JSONObject putOnce(String key, Object value) throws JSONException {
+ if (key != null && value != null) {
+ if (opt(key) != null) {
+ throw new JSONException("Duplicate key \"" + key + "\"");
+ }
+ put(key, value);
+ }
+ return this;
+ }
+
+ /**
+ * Put a key/value pair in the JSONObject, but only if the key and the value
+ * are both non-null.
+ *
+ * @param key
+ * A key string.
+ * @param value
+ * An object which is the value. It should be of one of these
+ * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
+ * String, or the JSONObject.NULL object.
+ * @return this.
+ * @throws JSONException
+ * If the value is a non-finite number.
+ */
+ public JSONObject putOpt(String key, Object value) throws JSONException {
+ if (key != null && value != null) {
+ put(key, value);
+ }
+ return this;
+ }
+
+ /**
+ * Produce a string in double quotes with backslash sequences in all the
+ * right places. A backslash will be inserted within </, producing <\/,
+ * allowing JSON text to be delivered in HTML. In JSON text, a string cannot
+ * contain a control character or an unescaped quote or backslash.
+ *
+ * @param string
+ * A String
+ * @return A String correctly formatted for insertion in a JSON text.
+ */
+ public static String quote(String string) {
+ if (string == null || string.length() == 0) {
+ return "\"\"";
+ }
+
+ char b;
+ char c = 0;
+ String hhhh;
+ int i;
+ int len = string.length();
+ StringBuffer sb = new StringBuffer(len + 4);
+
+ sb.append('"');
+ for (i = 0; i < len; i += 1) {
+ b = c;
+ c = string.charAt(i);
+ switch (c) {
+ case '\\':
+ case '"':
+ sb.append('\\');
+ sb.append(c);
+ break;
+ case '/':
+ if (b == '<') {
+ sb.append('\\');
+ }
+ sb.append(c);
+ break;
+ case '\b':
+ sb.append("\\b");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\f':
+ sb.append("\\f");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ default:
+ if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
+ || (c >= '\u2000' && c < '\u2100')) {
+ hhhh = "000" + Integer.toHexString(c);
+ sb.append("\\u" + hhhh.substring(hhhh.length() - 4));
+ } else {
+ sb.append(c);
+ }
+ }
+ }
+ sb.append('"');
+ return sb.toString();
+ }
+
+ /**
+ * Remove a name and its value, if present.
+ *
+ * @param key
+ * The name to be removed.
+ * @return The value that was associated with the name, or null if there was
+ * no value.
+ */
+ public Object remove(String key) {
+ return map.remove(key);
+ }
+
+ /**
+ * Try to convert a string into a number, boolean, or null. If the string
+ * can't be converted, return the string.
+ *
+ * @param string
+ * A String.
+ * @return A simple JSON value.
+ */
+ public static Object stringToValue(String string) {
+ Double d;
+ if (string.equals("")) {
+ return string;
+ }
+ if (string.equalsIgnoreCase("true")) {
+ return Boolean.TRUE;
+ }
+ if (string.equalsIgnoreCase("false")) {
+ return Boolean.FALSE;
+ }
+ if (string.equalsIgnoreCase("null")) {
+ return JSONObject.NULL;
+ }
+
+ /*
+ * If it might be a number, try converting it. We support the
+ * non-standard 0x- convention. If a number cannot be produced, then the
+ * value will just be a string. Note that the 0x-, plus, and implied
+ * string conventions are non-standard. A JSON parser may accept
+ * non-JSON forms as long as it accepts all correct JSON forms.
+ */
+
+ char b = string.charAt(0);
+ if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
+ if (b == '0' && string.length() > 2
+ && (string.charAt(1) == 'x' || string.charAt(1) == 'X')) {
+ try {
+ return new Integer(
+ Integer.parseInt(string.substring(2), 16));
+ } catch (Exception ignore) {
+ }
+ }
+ try {
+ if (string.indexOf('.') > -1 || string.indexOf('e') > -1
+ || string.indexOf('E') > -1) {
+ d = Double.valueOf(string);
+ if (!d.isInfinite() && !d.isNaN()) {
+ return d;
+ }
+ } else {
+ Long myLong = new Long(string);
+ if (myLong.longValue() == myLong.intValue()) {
+ return new Integer(myLong.intValue());
+ } else {
+ return myLong;
+ }
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ return string;
+ }
+
+ /**
+ * Throw an exception if the object is a NaN or infinite number.
+ *
+ * @param o
+ * The object to test.
+ * @throws JSONException
+ * If o is a non-finite number.
+ */
+ public static void testValidity(Object o) throws JSONException {
+ if (o != null) {
+ if (o instanceof Double) {
+ if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
+ throw new JSONException(
+ "JSON does not allow non-finite numbers.");
+ }
+ } else if (o instanceof Float) {
+ if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
+ throw new JSONException(
+ "JSON does not allow non-finite numbers.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Produce a JSONArray containing the values of the members of this
+ * JSONObject.
+ *
+ * @param names
+ * A JSONArray containing a list of key strings. This determines
+ * the sequence of the values in the result.
+ * @return A JSONArray of values.
+ * @throws JSONException
+ * If any of the values are non-finite numbers.
+ */
+ public JSONArray toJSONArray(JSONArray names) throws JSONException {
+ if (names == null || names.length() == 0) {
+ return null;
+ }
+ JSONArray ja = new JSONArray();
+ for (int i = 0; i < names.length(); i += 1) {
+ ja.put(opt(names.getString(i)));
+ }
+ return ja;
+ }
+
+ /**
+ * Make a JSON text of this JSONObject. For compactness, no whitespace is
+ * added. If this would not result in a syntactically correct JSON text,
+ * then null will be returned instead.
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return a printable, displayable, portable, transmittable representation
+ * of the object, beginning with <code>{</code>&nbsp;<small>(left
+ * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
+ * brace)</small>.
+ */
+ @Override
+ public String toString() {
+ try {
+ Iterator keys = keys();
+ StringBuffer sb = new StringBuffer("{");
+
+ while (keys.hasNext()) {
+ if (sb.length() > 1) {
+ sb.append(',');
+ }
+ Object o = keys.next();
+ sb.append(quote(o.toString()));
+ sb.append(':');
+ sb.append(valueToString(map.get(o)));
+ }
+ sb.append('}');
+ return sb.toString();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Make a prettyprinted JSON text of this JSONObject.
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @param indentFactor
+ * The number of spaces to add to each level of indentation.
+ * @return a printable, displayable, portable, transmittable representation
+ * of the object, beginning with <code>{</code>&nbsp;<small>(left
+ * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
+ * brace)</small>.
+ * @throws JSONException
+ * If the object contains an invalid number.
+ */
+ public String toString(int indentFactor) throws JSONException {
+ return toString(indentFactor, 0);
+ }
+
+ /**
+ * Make a prettyprinted JSON text of this JSONObject.
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @param indentFactor
+ * The number of spaces to add to each level of indentation.
+ * @param indent
+ * The indentation of the top level.
+ * @return a printable, displayable, transmittable representation of the
+ * object, beginning with <code>{</code>&nbsp;<small>(left
+ * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
+ * brace)</small>.
+ * @throws JSONException
+ * If the object contains an invalid number.
+ */
+ String toString(int indentFactor, int indent) throws JSONException {
+ int i;
+ int length = length();
+ if (length == 0) {
+ return "{}";
+ }
+ Iterator keys = keys();
+ int newindent = indent + indentFactor;
+ Object object;
+ StringBuffer sb = new StringBuffer("{");
+ if (length == 1) {
+ object = keys.next();
+ sb.append(quote(object.toString()));
+ sb.append(": ");
+ sb.append(valueToString(map.get(object), indentFactor, indent));
+ } else {
+ while (keys.hasNext()) {
+ object = keys.next();
+ if (sb.length() > 1) {
+ sb.append(",\n");
+ } else {
+ sb.append('\n');
+ }
+ for (i = 0; i < newindent; i += 1) {
+ sb.append(' ');
+ }
+ sb.append(quote(object.toString()));
+ sb.append(": ");
+ sb.append(valueToString(map.get(object), indentFactor,
+ newindent));
+ }
+ if (sb.length() > 1) {
+ sb.append('\n');
+ for (i = 0; i < indent; i += 1) {
+ sb.append(' ');
+ }
+ }
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+
+ /**
+ * Make a JSON text of an Object value. If the object has an
+ * value.toJSONString() method, then that method will be used to produce the
+ * JSON text. The method is required to produce a strictly conforming text.
+ * If the object does not contain a toJSONString method (which is the most
+ * common case), then a text will be produced by other means. If the value
+ * is an array or Collection, then a JSONArray will be made from it and its
+ * toJSONString method will be called. If the value is a MAP, then a
+ * JSONObject will be made from it and its toJSONString method will be
+ * called. Otherwise, the value's toString method will be called, and the
+ * result will be quoted.
+ *
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @param value
+ * The value to be serialized.
+ * @return a printable, displayable, transmittable representation of the
+ * object, beginning with <code>{</code>&nbsp;<small>(left
+ * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
+ * brace)</small>.
+ * @throws JSONException
+ * If the value is or contains an invalid number.
+ */
+ public static String valueToString(Object value) throws JSONException {
+ if (value == null || value.equals(null)) {
+ return "null";
+ }
+ if (value instanceof JSONString) {
+ Object object;
+ try {
+ object = ((JSONString) value).toJSONString();
+ } catch (Exception e) {
+ throw new JSONException(e);
+ }
+ if (object instanceof String) {
+ return (String) object;
+ }
+ throw new JSONException("Bad value from toJSONString: " + object);
+ }
+ if (value instanceof Number) {
+ return numberToString((Number) value);
+ }
+ if (value instanceof Boolean || value instanceof JSONObject
+ || value instanceof JSONArray) {
+ return value.toString();
+ }
+ if (value instanceof Map) {
+ return new JSONObject((Map) value).toString();
+ }
+ if (value instanceof Collection) {
+ return new JSONArray((Collection) value).toString();
+ }
+ if (value.getClass().isArray()) {
+ return new JSONArray(value).toString();
+ }
+ return quote(value.toString());
+ }
+
+ /**
+ * Make a prettyprinted JSON text of an object value.
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @param value
+ * The value to be serialized.
+ * @param indentFactor
+ * The number of spaces to add to each level of indentation.
+ * @param indent
+ * The indentation of the top level.
+ * @return a printable, displayable, transmittable representation of the
+ * object, beginning with <code>{</code>&nbsp;<small>(left
+ * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
+ * brace)</small>.
+ * @throws JSONException
+ * If the object contains an invalid number.
+ */
+ static String valueToString(Object value, int indentFactor, int indent)
+ throws JSONException {
+ if (value == null || value.equals(null)) {
+ return "null";
+ }
+ try {
+ if (value instanceof JSONString) {
+ Object o = ((JSONString) value).toJSONString();
+ if (o instanceof String) {
+ return (String) o;
+ }
+ }
+ } catch (Exception ignore) {
+ }
+ if (value instanceof Number) {
+ return numberToString((Number) value);
+ }
+ if (value instanceof Boolean) {
+ return value.toString();
+ }
+ if (value instanceof JSONObject) {
+ return ((JSONObject) value).toString(indentFactor, indent);
+ }
+ if (value instanceof JSONArray) {
+ return ((JSONArray) value).toString(indentFactor, indent);
+ }
+ if (value instanceof Map) {
+ return new JSONObject((Map) value).toString(indentFactor, indent);
+ }
+ if (value instanceof Collection) {
+ return new JSONArray((Collection) value).toString(indentFactor,
+ indent);
+ }
+ if (value.getClass().isArray()) {
+ return new JSONArray(value).toString(indentFactor, indent);
+ }
+ return quote(value.toString());
+ }
+
+ /**
+ * Wrap an object, if necessary. If the object is null, return the NULL
+ * object. If it is an array or collection, wrap it in a JSONArray. If it is
+ * a map, wrap it in a JSONObject. If it is a standard property (Double,
+ * String, et al) then it is already wrapped. Otherwise, if it comes from
+ * one of the java packages, turn it into a string. And if it doesn't, try
+ * to wrap it in a JSONObject. If the wrapping fails, then null is returned.
+ *
+ * @param object
+ * The object to wrap
+ * @return The wrapped value
+ */
+ public static Object wrap(Object object) {
+ try {
+ if (object == null) {
+ return NULL;
+ }
+ if (object instanceof JSONObject || object instanceof JSONArray
+ || NULL.equals(object) || object instanceof JSONString
+ || object instanceof Byte || object instanceof Character
+ || object instanceof Short || object instanceof Integer
+ || object instanceof Long || object instanceof Boolean
+ || object instanceof Float || object instanceof Double
+ || object instanceof String) {
+ return object;
+ }
+
+ if (object instanceof Collection) {
+ return new JSONArray((Collection) object);
+ }
+ if (object.getClass().isArray()) {
+ return new JSONArray(object);
+ }
+ if (object instanceof Map) {
+ return new JSONObject((Map) object);
+ }
+ Package objectPackage = object.getClass().getPackage();
+ String objectPackageName = objectPackage != null ? objectPackage
+ .getName() : "";
+ if (objectPackageName.startsWith("java.")
+ || objectPackageName.startsWith("javax.")
+ || object.getClass().getClassLoader() == null) {
+ return object.toString();
+ }
+ return new JSONObject(object);
+ } catch (Exception exception) {
+ return null;
+ }
+ }
+
+ /**
+ * Write the contents of the JSONObject as JSON text to a writer. For
+ * compactness, no whitespace is added.
+ * <p>
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @return The writer.
+ * @throws JSONException
+ */
+ public Writer write(Writer writer) throws JSONException {
+ try {
+ boolean commanate = false;
+ Iterator keys = keys();
+ writer.write('{');
+
+ while (keys.hasNext()) {
+ if (commanate) {
+ writer.write(',');
+ }
+ Object key = keys.next();
+ writer.write(quote(key.toString()));
+ writer.write(':');
+ Object value = map.get(key);
+ if (value instanceof JSONObject) {
+ ((JSONObject) value).write(writer);
+ } else if (value instanceof JSONArray) {
+ ((JSONArray) value).write(writer);
+ } else {
+ writer.write(valueToString(value));
+ }
+ commanate = true;
+ }
+ writer.write('}');
+ return writer;
+ } catch (IOException exception) {
+ throw new JSONException(exception);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/external/json/JSONString.java b/src/com/vaadin/external/json/JSONString.java
new file mode 100644
index 0000000000..cc7e4d8c07
--- /dev/null
+++ b/src/com/vaadin/external/json/JSONString.java
@@ -0,0 +1,21 @@
+package com.vaadin.external.json;
+
+import java.io.Serializable;
+
+/**
+ * The <code>JSONString</code> interface allows a <code>toJSONString()</code>
+ * method so that a class can change the behavior of
+ * <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>, and
+ * <code>JSONWriter.value(</code>Object<code>)</code>. The
+ * <code>toJSONString</code> method will be used instead of the default behavior
+ * of using the Object's <code>toString()</code> method and quoting the result.
+ */
+public interface JSONString extends Serializable {
+ /**
+ * The <code>toJSONString</code> method allows a class to produce its own
+ * JSON serialization.
+ *
+ * @return A strictly syntactically correct JSON text.
+ */
+ public String toJSONString();
+}
diff --git a/src/com/vaadin/external/json/JSONStringer.java b/src/com/vaadin/external/json/JSONStringer.java
new file mode 100644
index 0000000000..465f27aaab
--- /dev/null
+++ b/src/com/vaadin/external/json/JSONStringer.java
@@ -0,0 +1,78 @@
+package com.vaadin.external.json;
+
+/*
+Copyright (c) 2006 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.io.StringWriter;
+
+/**
+ * JSONStringer provides a quick and convenient way of producing JSON text.
+ * The texts produced strictly conform to JSON syntax rules. No whitespace is
+ * added, so the results are ready for transmission or storage. Each instance of
+ * JSONStringer can produce one JSON text.
+ * <p>
+ * A JSONStringer instance provides a <code>value</code> method for appending
+ * values to the
+ * text, and a <code>key</code>
+ * method for adding keys before values in objects. There are <code>array</code>
+ * and <code>endArray</code> methods that make and bound array values, and
+ * <code>object</code> and <code>endObject</code> methods which make and bound
+ * object values. All of these methods return the JSONWriter instance,
+ * permitting cascade style. For example, <pre>
+ * myString = new JSONStringer()
+ * .object()
+ * .key("JSON")
+ * .value("Hello, World!")
+ * .endObject()
+ * .toString();</pre> which produces the string <pre>
+ * {"JSON":"Hello, World!"}</pre>
+ * <p>
+ * The first method called must be <code>array</code> or <code>object</code>.
+ * There are no methods for adding commas or colons. JSONStringer adds them for
+ * you. Objects and arrays can be nested up to 20 levels deep.
+ * <p>
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONStringer extends JSONWriter {
+ /**
+ * Make a fresh JSONStringer. It can be used to build one JSON text.
+ */
+ public JSONStringer() {
+ super(new StringWriter());
+ }
+
+ /**
+ * Return the JSON text. This method is used to obtain the product of the
+ * JSONStringer instance. It will return <code>null</code> if there was a
+ * problem in the construction of the JSON text (such as the calls to
+ * <code>array</code> were not properly balanced with calls to
+ * <code>endArray</code>).
+ * @return The JSON text.
+ */
+ public String toString() {
+ return this.mode == 'd' ? this.writer.toString() : null;
+ }
+}
diff --git a/src/com/vaadin/external/json/JSONTokener.java b/src/com/vaadin/external/json/JSONTokener.java
new file mode 100644
index 0000000000..c3531cae1d
--- /dev/null
+++ b/src/com/vaadin/external/json/JSONTokener.java
@@ -0,0 +1,451 @@
+package com.vaadin.external.json;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+
+/*
+ Copyright (c) 2002 JSON.org
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ The Software shall be used for Good, not Evil.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+/**
+ * A JSONTokener takes a source string and extracts characters and tokens from
+ * it. It is used by the JSONObject and JSONArray constructors to parse JSON
+ * source strings.
+ *
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class JSONTokener implements Serializable {
+
+ private int character;
+ private boolean eof;
+ private int index;
+ private int line;
+ private char previous;
+ private Reader reader;
+ private boolean usePrevious;
+
+ /**
+ * Construct a JSONTokener from a Reader.
+ *
+ * @param reader
+ * A reader.
+ */
+ public JSONTokener(Reader reader) {
+ this.reader = reader.markSupported() ? reader : new BufferedReader(
+ reader);
+ eof = false;
+ usePrevious = false;
+ previous = 0;
+ index = 0;
+ character = 1;
+ line = 1;
+ }
+
+ /**
+ * Construct a JSONTokener from an InputStream.
+ */
+ public JSONTokener(InputStream inputStream) throws JSONException {
+ this(new InputStreamReader(inputStream));
+ }
+
+ /**
+ * Construct a JSONTokener from a string.
+ *
+ * @param s
+ * A source string.
+ */
+ public JSONTokener(String s) {
+ this(new StringReader(s));
+ }
+
+ /**
+ * Back up one character. This provides a sort of lookahead capability, so
+ * that you can test for a digit or letter before attempting to parse the
+ * next number or identifier.
+ */
+ public void back() throws JSONException {
+ if (usePrevious || index <= 0) {
+ throw new JSONException("Stepping back two steps is not supported");
+ }
+ index -= 1;
+ character -= 1;
+ usePrevious = true;
+ eof = false;
+ }
+
+ /**
+ * Get the hex value of a character (base16).
+ *
+ * @param c
+ * A character between '0' and '9' or between 'A' and 'F' or
+ * between 'a' and 'f'.
+ * @return An int between 0 and 15, or -1 if c was not a hex digit.
+ */
+ public static int dehexchar(char c) {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ }
+ if (c >= 'A' && c <= 'F') {
+ return c - ('A' - 10);
+ }
+ if (c >= 'a' && c <= 'f') {
+ return c - ('a' - 10);
+ }
+ return -1;
+ }
+
+ public boolean end() {
+ return eof && !usePrevious;
+ }
+
+ /**
+ * Determine if the source string still contains characters that next() can
+ * consume.
+ *
+ * @return true if not yet at the end of the source.
+ */
+ public boolean more() throws JSONException {
+ next();
+ if (end()) {
+ return false;
+ }
+ back();
+ return true;
+ }
+
+ /**
+ * Get the next character in the source string.
+ *
+ * @return The next character, or 0 if past the end of the source string.
+ */
+ public char next() throws JSONException {
+ int c;
+ if (usePrevious) {
+ usePrevious = false;
+ c = previous;
+ } else {
+ try {
+ c = reader.read();
+ } catch (IOException exception) {
+ throw new JSONException(exception);
+ }
+
+ if (c <= 0) { // End of stream
+ eof = true;
+ c = 0;
+ }
+ }
+ index += 1;
+ if (previous == '\r') {
+ line += 1;
+ character = c == '\n' ? 0 : 1;
+ } else if (c == '\n') {
+ line += 1;
+ character = 0;
+ } else {
+ character += 1;
+ }
+ previous = (char) c;
+ return previous;
+ }
+
+ /**
+ * Consume the next character, and check that it matches a specified
+ * character.
+ *
+ * @param c
+ * The character to match.
+ * @return The character.
+ * @throws JSONException
+ * if the character does not match.
+ */
+ public char next(char c) throws JSONException {
+ char n = next();
+ if (n != c) {
+ throw syntaxError("Expected '" + c + "' and instead saw '" + n
+ + "'");
+ }
+ return n;
+ }
+
+ /**
+ * Get the next n characters.
+ *
+ * @param n
+ * The number of characters to take.
+ * @return A string of n characters.
+ * @throws JSONException
+ * Substring bounds error if there are not n characters
+ * remaining in the source string.
+ */
+ public String next(int n) throws JSONException {
+ if (n == 0) {
+ return "";
+ }
+
+ char[] chars = new char[n];
+ int pos = 0;
+
+ while (pos < n) {
+ chars[pos] = next();
+ if (end()) {
+ throw syntaxError("Substring bounds error");
+ }
+ pos += 1;
+ }
+ return new String(chars);
+ }
+
+ /**
+ * Get the next char in the string, skipping whitespace.
+ *
+ * @throws JSONException
+ * @return A character, or 0 if there are no more characters.
+ */
+ public char nextClean() throws JSONException {
+ for (;;) {
+ char c = next();
+ if (c == 0 || c > ' ') {
+ return c;
+ }
+ }
+ }
+
+ /**
+ * Return the characters up to the next close quote character. Backslash
+ * processing is done. The formal JSON format does not allow strings in
+ * single quotes, but an implementation is allowed to accept them.
+ *
+ * @param quote
+ * The quoting character, either <code>"</code>
+ * &nbsp;<small>(double quote)</small> or <code>'</code>
+ * &nbsp;<small>(single quote)</small>.
+ * @return A String.
+ * @throws JSONException
+ * Unterminated string.
+ */
+ public String nextString(char quote) throws JSONException {
+ char c;
+ StringBuffer sb = new StringBuffer();
+ for (;;) {
+ c = next();
+ switch (c) {
+ case 0:
+ case '\n':
+ case '\r':
+ throw syntaxError("Unterminated string");
+ case '\\':
+ c = next();
+ switch (c) {
+ case 'b':
+ sb.append('\b');
+ break;
+ case 't':
+ sb.append('\t');
+ break;
+ case 'n':
+ sb.append('\n');
+ break;
+ case 'f':
+ sb.append('\f');
+ break;
+ case 'r':
+ sb.append('\r');
+ break;
+ case 'u':
+ sb.append((char) Integer.parseInt(next(4), 16));
+ break;
+ case '"':
+ case '\'':
+ case '\\':
+ case '/':
+ sb.append(c);
+ break;
+ default:
+ throw syntaxError("Illegal escape.");
+ }
+ break;
+ default:
+ if (c == quote) {
+ return sb.toString();
+ }
+ sb.append(c);
+ }
+ }
+ }
+
+ /**
+ * Get the text up but not including the specified character or the end of
+ * line, whichever comes first.
+ *
+ * @param delimiter
+ * A delimiter character.
+ * @return A string.
+ */
+ public String nextTo(char delimiter) throws JSONException {
+ StringBuffer sb = new StringBuffer();
+ for (;;) {
+ char c = next();
+ if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
+ if (c != 0) {
+ back();
+ }
+ return sb.toString().trim();
+ }
+ sb.append(c);
+ }
+ }
+
+ /**
+ * Get the text up but not including one of the specified delimiter
+ * characters or the end of line, whichever comes first.
+ *
+ * @param delimiters
+ * A set of delimiter characters.
+ * @return A string, trimmed.
+ */
+ public String nextTo(String delimiters) throws JSONException {
+ char c;
+ StringBuffer sb = new StringBuffer();
+ for (;;) {
+ c = next();
+ if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') {
+ if (c != 0) {
+ back();
+ }
+ return sb.toString().trim();
+ }
+ sb.append(c);
+ }
+ }
+
+ /**
+ * Get the next value. The value can be a Boolean, Double, Integer,
+ * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
+ *
+ * @throws JSONException
+ * If syntax error.
+ *
+ * @return An object.
+ */
+ public Object nextValue() throws JSONException {
+ char c = nextClean();
+ String string;
+
+ switch (c) {
+ case '"':
+ case '\'':
+ return nextString(c);
+ case '{':
+ back();
+ return new JSONObject(this);
+ case '[':
+ back();
+ return new JSONArray(this);
+ }
+
+ /*
+ * Handle unquoted text. This could be the values true, false, or null,
+ * or it can be a number. An implementation (such as this one) is
+ * allowed to also accept non-standard forms.
+ *
+ * Accumulate characters until we reach the end of the text or a
+ * formatting character.
+ */
+
+ StringBuffer sb = new StringBuffer();
+ while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
+ sb.append(c);
+ c = next();
+ }
+ back();
+
+ string = sb.toString().trim();
+ if (string.equals("")) {
+ throw syntaxError("Missing value");
+ }
+ return JSONObject.stringToValue(string);
+ }
+
+ /**
+ * Skip characters until the next character is the requested character. If
+ * the requested character is not found, no characters are skipped.
+ *
+ * @param to
+ * A character to skip to.
+ * @return The requested character, or zero if the requested character is
+ * not found.
+ */
+ public char skipTo(char to) throws JSONException {
+ char c;
+ try {
+ int startIndex = index;
+ int startCharacter = character;
+ int startLine = line;
+ reader.mark(Integer.MAX_VALUE);
+ do {
+ c = next();
+ if (c == 0) {
+ reader.reset();
+ index = startIndex;
+ character = startCharacter;
+ line = startLine;
+ return c;
+ }
+ } while (c != to);
+ } catch (IOException exc) {
+ throw new JSONException(exc);
+ }
+
+ back();
+ return c;
+ }
+
+ /**
+ * Make a JSONException to signal a syntax error.
+ *
+ * @param message
+ * The error message.
+ * @return A JSONException object, suitable for throwing
+ */
+ public JSONException syntaxError(String message) {
+ return new JSONException(message + toString());
+ }
+
+ /**
+ * Make a printable string of this JSONTokener.
+ *
+ * @return " at {index} [character {character} line {line}]"
+ */
+ @Override
+ public String toString() {
+ return " at " + index + " [character " + character + " line " + line
+ + "]";
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/external/json/JSONWriter.java b/src/com/vaadin/external/json/JSONWriter.java
new file mode 100644
index 0000000000..5f9ddeeae2
--- /dev/null
+++ b/src/com/vaadin/external/json/JSONWriter.java
@@ -0,0 +1,355 @@
+package com.vaadin.external.json;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+
+/*
+ Copyright (c) 2006 JSON.org
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ The Software shall be used for Good, not Evil.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ */
+
+/**
+ * JSONWriter provides a quick and convenient way of producing JSON text. The
+ * texts produced strictly conform to JSON syntax rules. No whitespace is added,
+ * so the results are ready for transmission or storage. Each instance of
+ * JSONWriter can produce one JSON text.
+ * <p>
+ * A JSONWriter instance provides a <code>value</code> method for appending
+ * values to the text, and a <code>key</code> method for adding keys before
+ * values in objects. There are <code>array</code> and <code>endArray</code>
+ * methods that make and bound array values, and <code>object</code> and
+ * <code>endObject</code> methods which make and bound object values. All of
+ * these methods return the JSONWriter instance, permitting a cascade style. For
+ * example,
+ *
+ * <pre>
+ * new JSONWriter(myWriter).object().key(&quot;JSON&quot;).value(&quot;Hello, World!&quot;)
+ * .endObject();
+ * </pre>
+ *
+ * which writes
+ *
+ * <pre>
+ * {"JSON":"Hello, World!"}
+ * </pre>
+ * <p>
+ * The first method called must be <code>array</code> or <code>object</code>.
+ * There are no methods for adding commas or colons. JSONWriter adds them for
+ * you. Objects and arrays can be nested up to 20 levels deep.
+ * <p>
+ * This can sometimes be easier than using a JSONObject to build a string.
+ *
+ * @author JSON.org
+ * @version 2011-11-14
+ */
+public class JSONWriter implements Serializable {
+ private static final int maxdepth = 200;
+
+ /**
+ * The comma flag determines if a comma should be output before the next
+ * value.
+ */
+ private boolean comma;
+
+ /**
+ * The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k'
+ * (key), 'o' (object).
+ */
+ protected char mode;
+
+ /**
+ * The object/array stack.
+ */
+ private final JSONObject stack[];
+
+ /**
+ * The stack top index. A value of 0 indicates that the stack is empty.
+ */
+ private int top;
+
+ /**
+ * The writer that will receive the output.
+ */
+ protected Writer writer;
+
+ /**
+ * Make a fresh JSONWriter. It can be used to build one JSON text.
+ */
+ public JSONWriter(Writer w) {
+ comma = false;
+ mode = 'i';
+ stack = new JSONObject[maxdepth];
+ top = 0;
+ writer = w;
+ }
+
+ /**
+ * Append a value.
+ *
+ * @param string
+ * A string value.
+ * @return this
+ * @throws JSONException
+ * If the value is out of sequence.
+ */
+ private JSONWriter append(String string) throws JSONException {
+ if (string == null) {
+ throw new JSONException("Null pointer");
+ }
+ if (mode == 'o' || mode == 'a') {
+ try {
+ if (comma && mode == 'a') {
+ writer.write(',');
+ }
+ writer.write(string);
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ if (mode == 'o') {
+ mode = 'k';
+ }
+ comma = true;
+ return this;
+ }
+ throw new JSONException("Value out of sequence.");
+ }
+
+ /**
+ * Begin appending a new array. All values until the balancing
+ * <code>endArray</code> will be appended to this array. The
+ * <code>endArray</code> method must be called to mark the array's end.
+ *
+ * @return this
+ * @throws JSONException
+ * If the nesting is too deep, or if the object is started in
+ * the wrong place (for example as a key or after the end of the
+ * outermost array or object).
+ */
+ public JSONWriter array() throws JSONException {
+ if (mode == 'i' || mode == 'o' || mode == 'a') {
+ push(null);
+ append("[");
+ comma = false;
+ return this;
+ }
+ throw new JSONException("Misplaced array.");
+ }
+
+ /**
+ * End something.
+ *
+ * @param mode
+ * Mode
+ * @param c
+ * Closing character
+ * @return this
+ * @throws JSONException
+ * If unbalanced.
+ */
+ private JSONWriter end(char mode, char c) throws JSONException {
+ if (this.mode != mode) {
+ throw new JSONException(mode == 'a' ? "Misplaced endArray."
+ : "Misplaced endObject.");
+ }
+ pop(mode);
+ try {
+ writer.write(c);
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ comma = true;
+ return this;
+ }
+
+ /**
+ * End an array. This method most be called to balance calls to
+ * <code>array</code>.
+ *
+ * @return this
+ * @throws JSONException
+ * If incorrectly nested.
+ */
+ public JSONWriter endArray() throws JSONException {
+ return end('a', ']');
+ }
+
+ /**
+ * End an object. This method most be called to balance calls to
+ * <code>object</code>.
+ *
+ * @return this
+ * @throws JSONException
+ * If incorrectly nested.
+ */
+ public JSONWriter endObject() throws JSONException {
+ return end('k', '}');
+ }
+
+ /**
+ * Append a key. The key will be associated with the next value. In an
+ * object, every value must be preceded by a key.
+ *
+ * @param string
+ * A key string.
+ * @return this
+ * @throws JSONException
+ * If the key is out of place. For example, keys do not belong
+ * in arrays or if the key is null.
+ */
+ public JSONWriter key(String string) throws JSONException {
+ if (string == null) {
+ throw new JSONException("Null key.");
+ }
+ if (mode == 'k') {
+ try {
+ stack[top - 1].putOnce(string, Boolean.TRUE);
+ if (comma) {
+ writer.write(',');
+ }
+ writer.write(JSONObject.quote(string));
+ writer.write(':');
+ comma = false;
+ mode = 'o';
+ return this;
+ } catch (IOException e) {
+ throw new JSONException(e);
+ }
+ }
+ throw new JSONException("Misplaced key.");
+ }
+
+ /**
+ * Begin appending a new object. All keys and values until the balancing
+ * <code>endObject</code> will be appended to this object. The
+ * <code>endObject</code> method must be called to mark the object's end.
+ *
+ * @return this
+ * @throws JSONException
+ * If the nesting is too deep, or if the object is started in
+ * the wrong place (for example as a key or after the end of the
+ * outermost array or object).
+ */
+ public JSONWriter object() throws JSONException {
+ if (mode == 'i') {
+ mode = 'o';
+ }
+ if (mode == 'o' || mode == 'a') {
+ append("{");
+ push(new JSONObject());
+ comma = false;
+ return this;
+ }
+ throw new JSONException("Misplaced object.");
+
+ }
+
+ /**
+ * Pop an array or object scope.
+ *
+ * @param c
+ * The scope to close.
+ * @throws JSONException
+ * If nesting is wrong.
+ */
+ private void pop(char c) throws JSONException {
+ if (top <= 0) {
+ throw new JSONException("Nesting error.");
+ }
+ char m = stack[top - 1] == null ? 'a' : 'k';
+ if (m != c) {
+ throw new JSONException("Nesting error.");
+ }
+ top -= 1;
+ mode = top == 0 ? 'd' : stack[top - 1] == null ? 'a' : 'k';
+ }
+
+ /**
+ * Push an array or object scope.
+ *
+ * @param c
+ * The scope to open.
+ * @throws JSONException
+ * If nesting is too deep.
+ */
+ private void push(JSONObject jo) throws JSONException {
+ if (top >= maxdepth) {
+ throw new JSONException("Nesting too deep.");
+ }
+ stack[top] = jo;
+ mode = jo == null ? 'a' : 'k';
+ top += 1;
+ }
+
+ /**
+ * Append either the value <code>true</code> or the value <code>false</code>
+ * .
+ *
+ * @param b
+ * A boolean.
+ * @return this
+ * @throws JSONException
+ */
+ public JSONWriter value(boolean b) throws JSONException {
+ return append(b ? "true" : "false");
+ }
+
+ /**
+ * Append a double value.
+ *
+ * @param d
+ * A double.
+ * @return this
+ * @throws JSONException
+ * If the number is not finite.
+ */
+ public JSONWriter value(double d) throws JSONException {
+ return this.value(new Double(d));
+ }
+
+ /**
+ * Append a long value.
+ *
+ * @param l
+ * A long.
+ * @return this
+ * @throws JSONException
+ */
+ public JSONWriter value(long l) throws JSONException {
+ return append(Long.toString(l));
+ }
+
+ /**
+ * Append an object value.
+ *
+ * @param object
+ * The object to append. It can be null, or a Boolean, Number,
+ * String, JSONObject, or JSONArray, or an object that implements
+ * JSONString.
+ * @return this
+ * @throws JSONException
+ * If the value is out of sequence.
+ */
+ public JSONWriter value(Object object) throws JSONException {
+ return append(JSONObject.valueToString(object));
+ }
+}
diff --git a/src/com/vaadin/external/json/README b/src/com/vaadin/external/json/README
new file mode 100644
index 0000000000..ca6dc11764
--- /dev/null
+++ b/src/com/vaadin/external/json/README
@@ -0,0 +1,68 @@
+JSON in Java [package org.json]
+
+Douglas Crockford
+douglas@crockford.com
+
+2011-02-02
+
+
+JSON is a light-weight, language independent, data interchange format.
+See http://www.JSON.org/
+
+The files in this package implement JSON encoders/decoders in Java.
+It also includes the capability to convert between JSON and XML, HTTP
+headers, Cookies, and CDL.
+
+This is a reference implementation. There is a large number of JSON packages
+in Java. Perhaps someday the Java community will standardize on one. Until
+then, choose carefully.
+
+The license includes this restriction: "The software shall be used for good,
+not evil." If your conscience cannot live with that, then choose a different
+package.
+
+The package compiles on Java 1.2 thru Java 1.4.
+
+
+JSONObject.java: The JSONObject can parse text from a String or a JSONTokener
+to produce a map-like object. The object provides methods for manipulating its
+contents, and for producing a JSON compliant object serialization.
+
+JSONArray.java: The JSONObject can parse text from a String or a JSONTokener
+to produce a vector-like object. The object provides methods for manipulating
+its contents, and for producing a JSON compliant array serialization.
+
+JSONTokener.java: The JSONTokener breaks a text into a sequence of individual
+tokens. It can be constructed from a String, Reader, or InputStream.
+
+JSONException.java: The JSONException is the standard exception type thrown
+by this package.
+
+
+JSONString.java: The JSONString interface requires a toJSONString method,
+allowing an object to provide its own serialization.
+
+JSONStringer.java: The JSONStringer provides a convenient facility for
+building JSON strings.
+
+JSONWriter.java: The JSONWriter provides a convenient facility for building
+JSON text through a writer.
+
+
+CDL.java: CDL provides support for converting between JSON and comma
+delimited lists.
+
+Cookie.java: Cookie provides support for converting between JSON and cookies.
+
+CookieList.java: CookieList provides support for converting between JSON and
+cookie lists.
+
+HTTP.java: HTTP provides support for converting between JSON and HTTP headers.
+
+HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers.
+
+XML.java: XML provides support for converting between JSON and XML.
+
+JSONML.java: JSONML provides support for converting between JSONML and XML.
+
+XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text. \ No newline at end of file
diff --git a/src/com/vaadin/terminal/CombinedRequest.java b/src/com/vaadin/terminal/CombinedRequest.java
new file mode 100644
index 0000000000..ccef6d8963
--- /dev/null
+++ b/src/com/vaadin/terminal/CombinedRequest.java
@@ -0,0 +1,167 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import com.vaadin.Application;
+import com.vaadin.external.json.JSONArray;
+import com.vaadin.external.json.JSONException;
+import com.vaadin.external.json.JSONObject;
+import com.vaadin.terminal.gwt.server.WebApplicationContext;
+import com.vaadin.terminal.gwt.server.WebBrowser;
+
+/**
+ * A {@link WrappedRequest} with path and parameters from one request and
+ * {@link WrappedRequest.BrowserDetails} extracted from another request.
+ *
+ * This class is intended to be used for a two request initialization where the
+ * first request fetches the actual application page and the second request
+ * contains information extracted from the browser using javascript.
+ *
+ */
+public class CombinedRequest implements WrappedRequest {
+
+ private final WrappedRequest secondRequest;
+ private Map<String, String[]> parameterMap;
+
+ /**
+ * Creates a new combined request based on the second request and some
+ * details from the first request.
+ *
+ * @param secondRequest
+ * the second request which will be used as the foundation of the
+ * combined request
+ * @throws JSONException
+ * if the initialParams parameter can not be decoded
+ */
+ public CombinedRequest(WrappedRequest secondRequest) throws JSONException {
+ this.secondRequest = secondRequest;
+
+ HashMap<String, String[]> map = new HashMap<String, String[]>();
+ JSONObject initialParams = new JSONObject(
+ secondRequest.getParameter("initialParams"));
+ for (Iterator<?> keys = initialParams.keys(); keys.hasNext();) {
+ String name = (String) keys.next();
+ JSONArray jsonValues = initialParams.getJSONArray(name);
+ String[] values = new String[jsonValues.length()];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = jsonValues.getString(i);
+ }
+ map.put(name, values);
+ }
+
+ parameterMap = Collections.unmodifiableMap(map);
+
+ }
+
+ public String getParameter(String parameter) {
+ String[] strings = getParameterMap().get(parameter);
+ if (strings == null || strings.length == 0) {
+ return null;
+ } else {
+ return strings[0];
+ }
+ }
+
+ public Map<String, String[]> getParameterMap() {
+ return parameterMap;
+ }
+
+ public int getContentLength() {
+ return secondRequest.getContentLength();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return secondRequest.getInputStream();
+ }
+
+ public Object getAttribute(String name) {
+ return secondRequest.getAttribute(name);
+ }
+
+ public void setAttribute(String name, Object value) {
+ secondRequest.setAttribute(name, value);
+ }
+
+ public String getRequestPathInfo() {
+ return secondRequest.getParameter("initialPath");
+ }
+
+ public int getSessionMaxInactiveInterval() {
+ return secondRequest.getSessionMaxInactiveInterval();
+ }
+
+ public Object getSessionAttribute(String name) {
+ return secondRequest.getSessionAttribute(name);
+ }
+
+ public void setSessionAttribute(String name, Object attribute) {
+ secondRequest.setSessionAttribute(name, attribute);
+ }
+
+ public String getContentType() {
+ return secondRequest.getContentType();
+ }
+
+ public BrowserDetails getBrowserDetails() {
+ return new BrowserDetails() {
+ public String getUriFragment() {
+ String fragment = secondRequest.getParameter("fr");
+ if (fragment == null) {
+ return "";
+ } else {
+ return fragment;
+ }
+ }
+
+ public String getWindowName() {
+ return secondRequest.getParameter("wn");
+ }
+
+ public WebBrowser getWebBrowser() {
+ WebApplicationContext context = (WebApplicationContext) Application
+ .getCurrentApplication().getContext();
+ return context.getBrowser();
+ }
+ };
+ }
+
+ /**
+ * Gets the original second request. This can be used e.g. if a request
+ * parameter from the second request is required.
+ *
+ * @return the original second wrapped request
+ */
+ public WrappedRequest getSecondRequest() {
+ return secondRequest;
+ }
+
+ public Locale getLocale() {
+ return secondRequest.getLocale();
+ }
+
+ public String getRemoteAddr() {
+ return secondRequest.getRemoteAddr();
+ }
+
+ public boolean isSecure() {
+ return secondRequest.isSecure();
+ }
+
+ public String getHeader(String name) {
+ return secondRequest.getHeader(name);
+ }
+
+ public DeploymentConfiguration getDeploymentConfiguration() {
+ return secondRequest.getDeploymentConfiguration();
+ }
+}
diff --git a/src/com/vaadin/terminal/CompositeErrorMessage.java b/src/com/vaadin/terminal/CompositeErrorMessage.java
index aae231739e..94f4e3a5d5 100644
--- a/src/com/vaadin/terminal/CompositeErrorMessage.java
+++ b/src/com/vaadin/terminal/CompositeErrorMessage.java
@@ -29,7 +29,7 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable {
/**
* Level of the error.
*/
- private int level;
+ private ErrorLevel level;
/**
* Constructor for CompositeErrorMessage.
@@ -40,7 +40,7 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable {
*/
public CompositeErrorMessage(ErrorMessage[] errorMessages) {
errors = new ArrayList<ErrorMessage>(errorMessages.length);
- level = Integer.MIN_VALUE;
+ level = ErrorLevel.INFORMATION;
for (int i = 0; i < errorMessages.length; i++) {
addErrorMessage(errorMessages[i]);
@@ -63,7 +63,7 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable {
public CompositeErrorMessage(
Collection<? extends ErrorMessage> errorMessages) {
errors = new ArrayList<ErrorMessage>(errorMessages.size());
- level = Integer.MIN_VALUE;
+ level = ErrorLevel.INFORMATION;
for (final Iterator<? extends ErrorMessage> i = errorMessages
.iterator(); i.hasNext();) {
@@ -81,7 +81,7 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable {
*
* @see com.vaadin.terminal.ErrorMessage#getErrorLevel()
*/
- public final int getErrorLevel() {
+ public final ErrorLevel getErrorLevel() {
return level;
}
@@ -95,9 +95,8 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable {
private void addErrorMessage(ErrorMessage error) {
if (error != null && !errors.contains(error)) {
errors.add(error);
- final int l = error.getErrorLevel();
- if (l > level) {
- level = l;
+ if (error.getErrorLevel().intValue() > level.intValue()) {
+ level = error.getErrorLevel();
}
}
}
@@ -120,18 +119,7 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable {
(errors.iterator().next()).paint(target);
} else {
target.startTag("error");
-
- if (level > 0 && level <= ErrorMessage.INFORMATION) {
- target.addAttribute("level", "info");
- } else if (level <= ErrorMessage.WARNING) {
- target.addAttribute("level", "warning");
- } else if (level <= ErrorMessage.ERROR) {
- target.addAttribute("level", "error");
- } else if (level <= ErrorMessage.CRITICAL) {
- target.addAttribute("level", "critical");
- } else {
- target.addAttribute("level", "system");
- }
+ target.addAttribute("level", level.getText());
// Paint all the exceptions
for (final Iterator<ErrorMessage> i = errors.iterator(); i
diff --git a/src/com/vaadin/terminal/DeploymentConfiguration.java b/src/com/vaadin/terminal/DeploymentConfiguration.java
new file mode 100644
index 0000000000..403a6d68b7
--- /dev/null
+++ b/src/com/vaadin/terminal/DeploymentConfiguration.java
@@ -0,0 +1,77 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal;
+
+import java.io.Serializable;
+
+/**
+ * Provide deployment specific settings that are required outside terminal
+ * specific code.
+ *
+ * @author Vaadin Ltd.
+ *
+ * @since 7.0
+ */
+public interface DeploymentConfiguration extends Serializable {
+
+ /**
+ * Gets the base URL of the location of Vaadin's static files.
+ *
+ * @param request
+ * the request for which the location should be determined
+ *
+ * @return a string with the base URL for static files
+ */
+ public String getStaticFileLocation(WrappedRequest request);
+
+ /**
+ * Gets the widgetset that is configured for this deployment, e.g. from a
+ * parameter in web.xml.
+ *
+ * @param request
+ * the request for which a widgetset is required
+ * @return the name of the widgetset
+ */
+ public String getConfiguredWidgetset(WrappedRequest request);
+
+ /**
+ * Gets the theme that is configured for this deployment, e.g. from a portal
+ * parameter or just some sensible default value.
+ *
+ * @param request
+ * the request for which a theme is required
+ * @return the name of the theme
+ */
+ public String getConfiguredTheme(WrappedRequest request);
+
+ /**
+ * Checks whether the Vaadin application will be rendered on its own in the
+ * browser or whether it will be included into some other context. A
+ * standalone application may do things that might interfere with other
+ * parts of a page, e.g. changing the page title and requesting focus upon
+ * loading.
+ *
+ * @param request
+ * the request for which the application is loaded
+ * @return a boolean indicating whether the application should be standalone
+ */
+ public boolean isStandalone(WrappedRequest request);
+
+ /**
+ * Gets a configured property. The properties are typically read from e.g.
+ * web.xml or from system properties of the JVM.
+ *
+ * @param propertyName
+ * The simple of the property, in some contexts, lookup might be
+ * performed using variations of the provided name.
+ * @param defaultValue
+ * the default value that should be used if no value has been
+ * defined
+ * @return the property value, or the passed default value if no property
+ * value is found
+ */
+ public String getApplicationOrSystemProperty(String propertyName,
+ String defaultValue);
+}
diff --git a/src/com/vaadin/terminal/DownloadStream.java b/src/com/vaadin/terminal/DownloadStream.java
index 2db2a1f20d..9853b0eee2 100644
--- a/src/com/vaadin/terminal/DownloadStream.java
+++ b/src/com/vaadin/terminal/DownloadStream.java
@@ -4,12 +4,18 @@
package com.vaadin.terminal;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import javax.servlet.http.HttpServletResponse;
+
+import com.vaadin.terminal.gwt.server.Constants;
+
/**
* Downloadable stream.
*
@@ -198,9 +204,132 @@ public class DownloadStream implements Serializable {
*
* @param bufferSize
* the size of the buffer in bytes.
+ *
+ * @since 7.0
*/
public void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}
+ /**
+ * Writes this download stream to a wrapped response. This takes care of
+ * setting response headers according to what is defined in this download
+ * stream ({@link #getContentType()}, {@link #getCacheTime()},
+ * {@link #getFileName()}) and transferring the data from the stream (
+ * {@link #getStream()}) to the response. Defined parameters (
+ * {@link #getParameterNames()}) are also included as headers in the
+ * response. If there's is a parameter named <code>Location</code>, a
+ * redirect (302 Moved temporarily) is sent instead of the contents of this
+ * stream.
+ *
+ * @param response
+ * the wrapped response to write this download stream to
+ * @throws IOException
+ * passed through from the wrapped response
+ *
+ * @since 7.0
+ */
+ public void writeTo(WrappedResponse response) throws IOException {
+ if (getParameter("Location") != null) {
+ response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ response.setHeader("Location", getParameter("Location"));
+ return;
+ }
+
+ // Download from given stream
+ final InputStream data = getStream();
+ if (data != null) {
+
+ OutputStream out = null;
+ try {
+ // Sets content type
+ response.setContentType(getContentType());
+
+ // Sets cache headers
+ response.setCacheTime(getCacheTime());
+
+ // Copy download stream parameters directly
+ // to HTTP headers.
+ final Iterator<String> i = getParameterNames();
+ if (i != null) {
+ while (i.hasNext()) {
+ final String param = i.next();
+ response.setHeader(param, getParameter(param));
+ }
+ }
+
+ // suggest local filename from DownloadStream if
+ // Content-Disposition
+ // not explicitly set
+ String contentDispositionValue = getParameter("Content-Disposition");
+ if (contentDispositionValue == null) {
+ contentDispositionValue = "filename=\"" + getFileName()
+ + "\"";
+ response.setHeader("Content-Disposition",
+ contentDispositionValue);
+ }
+
+ int bufferSize = getBufferSize();
+ if (bufferSize <= 0 || bufferSize > Constants.MAX_BUFFER_SIZE) {
+ bufferSize = Constants.DEFAULT_BUFFER_SIZE;
+ }
+ final byte[] buffer = new byte[bufferSize];
+ int bytesRead = 0;
+
+ out = response.getOutputStream();
+
+ long totalWritten = 0;
+ while ((bytesRead = data.read(buffer)) > 0) {
+ out.write(buffer, 0, bytesRead);
+
+ totalWritten += bytesRead;
+ if (totalWritten >= buffer.length) {
+ // Avoid chunked encoding for small resources
+ out.flush();
+ }
+ }
+ } finally {
+ tryToCloseStream(out);
+ tryToCloseStream(data);
+ }
+ }
+ }
+
+ /**
+ * Helper method that tries to close an output stream and ignores any
+ * exceptions.
+ *
+ * @param out
+ * the output stream to close, <code>null</code> is also
+ * supported
+ */
+ static void tryToCloseStream(OutputStream out) {
+ try {
+ // try to close output stream (e.g. file handle)
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException e1) {
+ // NOP
+ }
+ }
+
+ /**
+ * Helper method that tries to close an input stream and ignores any
+ * exceptions.
+ *
+ * @param in
+ * the input stream to close, <code>null</code> is also supported
+ */
+ static void tryToCloseStream(InputStream in) {
+ try {
+ // try to close output stream (e.g. file handle)
+ if (in != null) {
+ in.close();
+ }
+ } catch (IOException e1) {
+ // NOP
+ }
+ }
+
}
diff --git a/src/com/vaadin/terminal/ErrorMessage.java b/src/com/vaadin/terminal/ErrorMessage.java
index b3be407743..5e55bfbcf6 100644
--- a/src/com/vaadin/terminal/ErrorMessage.java
+++ b/src/com/vaadin/terminal/ErrorMessage.java
@@ -17,37 +17,98 @@ import java.io.Serializable;
*/
public interface ErrorMessage extends Paintable, Serializable {
+ public enum ErrorLevel {
+ /**
+ * Error code for informational messages.
+ */
+ INFORMATION("info", 0),
+ /**
+ * Error code for warning messages.
+ */
+ WARNING("warning", 1),
+ /**
+ * Error code for regular error messages.
+ */
+ ERROR("error", 2),
+ /**
+ * Error code for critical error messages.
+ */
+ CRITICAL("critical", 3),
+ /**
+ * Error code for system errors and bugs.
+ */
+ SYSTEMERROR("system", 4);
+
+ String text;
+ int errorLevel;
+
+ private ErrorLevel(String text, int errorLevel) {
+ this.text = text;
+ this.errorLevel = errorLevel;
+ }
+
+ /**
+ * Textual representation for server-client communication of level
+ *
+ * @return String for error severity
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Integer representation of error severity for comparison
+ *
+ * @return integer for error severity
+ */
+ public int intValue() {
+ return errorLevel;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+
+ }
+
/**
- * Error code for system errors and bugs.
+ * @deprecated from 7.0, use {@link ErrorLevel#SYSTEMERROR} instead    
*/
- public static final int SYSTEMERROR = 5000;
+ @Deprecated
+ public static final ErrorLevel SYSTEMERROR = ErrorLevel.SYSTEMERROR;
/**
- * Error code for critical error messages.
+ * @deprecated from 7.0, use {@link ErrorLevel#CRITICAL} instead    
*/
- public static final int CRITICAL = 4000;
+ @Deprecated
+ public static final ErrorLevel CRITICAL = ErrorLevel.CRITICAL;
/**
- * Error code for regular error messages.
+ * @deprecated from 7.0, use {@link ErrorLevel#ERROR} instead    
*/
- public static final int ERROR = 3000;
+
+ @Deprecated
+ public static final ErrorLevel ERROR = ErrorLevel.ERROR;
/**
- * Error code for warning messages.
+ * @deprecated from 7.0, use {@link ErrorLevel#WARNING} instead    
*/
- public static final int WARNING = 2000;
+ @Deprecated
+ public static final ErrorLevel WARNING = ErrorLevel.WARNING;
/**
- * Error code for informational messages.
+ * @deprecated from 7.0, use {@link ErrorLevel#INFORMATION} instead    
*/
- public static final int INFORMATION = 1000;
+ @Deprecated
+ public static final ErrorLevel INFORMATION = ErrorLevel.INFORMATION;
/**
* Gets the errors level.
*
* @return the level of error as an integer.
*/
- public int getErrorLevel();
+ public ErrorLevel getErrorLevel();
/**
* Error messages are inmodifiable and thus listeners are not needed. This
diff --git a/src/com/vaadin/terminal/ParameterHandler.java b/src/com/vaadin/terminal/ParameterHandler.java
deleted file mode 100644
index ef8a952e0e..0000000000
--- a/src/com/vaadin/terminal/ParameterHandler.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal;
-
-import java.io.Serializable;
-import java.util.Map;
-
-import com.vaadin.ui.Window;
-
-/**
- * {@code ParameterHandler} is implemented by classes capable of handling
- * external parameters.
- *
- * <p>
- * What parameters are provided depend on what the {@link Terminal} provides and
- * if the application is deployed as a servlet or portlet. URL GET parameters
- * are typically provided to the {@link #handleParameters(Map)} method.
- * </p>
- * <p>
- * A {@code ParameterHandler} must be registered to a {@code Window} using
- * {@link Window#addParameterHandler(ParameterHandler)} to be called when
- * parameters are available.
- * </p>
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public interface ParameterHandler extends Serializable {
-
- /**
- * Handles the given parameters. All parameters names are of type
- * {@link String} and the values are {@link String} arrays.
- *
- * @param parameters
- * an unmodifiable map which contains the parameter names and
- * values
- *
- */
- public void handleParameters(Map<String, String[]> parameters);
-
- /**
- * An ErrorEvent implementation for ParameterHandler.
- */
- public interface ErrorEvent extends Terminal.ErrorEvent {
-
- /**
- * Gets the ParameterHandler that caused the error.
- *
- * @return the ParameterHandler that caused the error
- */
- public ParameterHandler getParameterHandler();
-
- }
-
-}
diff --git a/src/com/vaadin/terminal/RequestHandler.java b/src/com/vaadin/terminal/RequestHandler.java
new file mode 100644
index 0000000000..f37201715d
--- /dev/null
+++ b/src/com/vaadin/terminal/RequestHandler.java
@@ -0,0 +1,36 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import com.vaadin.Application;
+
+/**
+ * Handler for producing a response to non-UIDL requests. Handlers can be added
+ * to applications using {@link Application#addRequestHandler(RequestHandler)}
+ */
+public interface RequestHandler extends Serializable {
+
+ /**
+ * Handles a non-UIDL request. If a response is written, this method should
+ * return <code>false</code> to indicate that no more request handlers
+ * should be invoked for the request.
+ *
+ * @param application
+ * The application to which the request belongs
+ * @param request
+ * The request to handle
+ * @param response
+ * The response object to which a response can be written.
+ * @return true if a response has been written and no further request
+ * handlers should be called, otherwise false
+ * @throws IOException
+ */
+ boolean handleRequest(Application application, WrappedRequest request,
+ WrappedResponse response) throws IOException;
+
+}
diff --git a/src/com/vaadin/terminal/Sizeable.java b/src/com/vaadin/terminal/Sizeable.java
index f5dc28b74c..e3c98e0fa9 100644
--- a/src/com/vaadin/terminal/Sizeable.java
+++ b/src/com/vaadin/terminal/Sizeable.java
@@ -18,71 +18,127 @@ import java.io.Serializable;
public interface Sizeable extends Serializable {
/**
- * Unit code representing pixels.
+ * @deprecated from 7.0, use {@link Unit#PIXELS} instead    
*/
- public static final int UNITS_PIXELS = 0;
+ @Deprecated
+ public static final Unit UNITS_PIXELS = Unit.PIXELS;
/**
- * Unit code representing points (1/72nd of an inch).
+ * @deprecated from 7.0, use {@link Unit#POINTS} instead    
*/
- public static final int UNITS_POINTS = 1;
+ @Deprecated
+ public static final Unit UNITS_POINTS = Unit.POINTS;
/**
- * Unit code representing picas (12 points).
+ * @deprecated from 7.0, use {@link Unit#PICAS} instead    
*/
- public static final int UNITS_PICAS = 2;
+ @Deprecated
+ public static final Unit UNITS_PICAS = Unit.PICAS;
/**
- * Unit code representing the font-size of the relevant font.
+ * @deprecated from 7.0, use {@link Unit#EM} instead    
*/
- public static final int UNITS_EM = 3;
+ @Deprecated
+ public static final Unit UNITS_EM = Unit.EM;
/**
- * Unit code representing the x-height of the relevant font.
+ * @deprecated from 7.0, use {@link Unit#EX} instead    
*/
- public static final int UNITS_EX = 4;
+ @Deprecated
+ public static final Unit UNITS_EX = Unit.EX;
/**
- * Unit code representing millimeters.
+ * @deprecated from 7.0, use {@link Unit#MM} instead    
*/
- public static final int UNITS_MM = 5;
+ @Deprecated
+ public static final Unit UNITS_MM = Unit.MM;
/**
- * Unit code representing centimeters.
+ * @deprecated from 7.0, use {@link Unit#CM} instead    
*/
- public static final int UNITS_CM = 6;
+ @Deprecated
+ public static final Unit UNITS_CM = Unit.CM;
/**
- * Unit code representing inches.
+ * @deprecated from 7.0, use {@link Unit#INCH} instead    
*/
- public static final int UNITS_INCH = 7;
+ @Deprecated
+ public static final Unit UNITS_INCH = Unit.INCH;
/**
- * Unit code representing in percentage of the containing element defined by
- * terminal.
+ * @deprecated from 7.0, use {@link Unit#PERCENTAGE} instead    
*/
- public static final int UNITS_PERCENTAGE = 8;
+ @Deprecated
+ public static final Unit UNITS_PERCENTAGE = Unit.PERCENTAGE;
public static final float SIZE_UNDEFINED = -1;
- /**
- * Textual representations of units symbols. Supported units and their
- * symbols are:
- * <ul>
- * <li>{@link #UNITS_PIXELS}: "px"</li>
- * <li>{@link #UNITS_POINTS}: "pt"</li>
- * <li>{@link #UNITS_PICAS}: "pc"</li>
- * <li>{@link #UNITS_EM}: "em"</li>
- * <li>{@link #UNITS_EX}: "ex"</li>
- * <li>{@link #UNITS_MM}: "mm"</li>
- * <li>{@link #UNITS_CM}. "cm"</li>
- * <li>{@link #UNITS_INCH}: "in"</li>
- * <li>{@link #UNITS_PERCENTAGE}: "%"</li>
- * </ul>
- * These can be used like <code>Sizeable.UNIT_SYMBOLS[UNITS_PIXELS]</code>.
- */
- public static final String[] UNIT_SYMBOLS = { "px", "pt", "pc", "em", "ex",
- "mm", "cm", "in", "%" };
+ public enum Unit {
+ /**
+ * Unit code representing pixels.
+ */
+ PIXELS("px"),
+ /**
+ * Unit code representing points (1/72nd of an inch).
+ */
+ POINTS("pt"),
+ /**
+ * Unit code representing picas (12 points).
+ */
+ PICAS("pc"),
+ /**
+ * Unit code representing the font-size of the relevant font.
+ */
+ EM("em"),
+ /**
+ * Unit code representing the x-height of the relevant font.
+ */
+ EX("ex"),
+ /**
+ * Unit code representing millimeters.
+ */
+ MM("mm"),
+ /**
+ * Unit code representing centimeters.
+ */
+ CM("cm"),
+ /**
+ * Unit code representing inches.
+ */
+ INCH("in"),
+ /**
+ * Unit code representing in percentage of the containing element
+ * defined by terminal.
+ */
+ PERCENTAGE("%");
+
+ private String symbol;
+
+ private Unit(String symbol) {
+ this.symbol = symbol;
+ }
+
+ public String getSymbol() {
+ return symbol;
+ }
+
+ @Override
+ public String toString() {
+ return symbol;
+ }
+
+ public static Unit getUnitFromSymbol(String symbol) {
+ if (symbol == null) {
+ return Unit.PIXELS; // Defaults to pixels
+ }
+ for (Unit unit : Unit.values()) {
+ if (symbol.equals(unit.getSymbol())) {
+ return unit;
+ }
+ }
+ return Unit.PIXELS; // Defaults to pixels
+ }
+ }
/**
* Gets the width of the object. Negative number implies unspecified size
@@ -93,21 +149,6 @@ public interface Sizeable extends Serializable {
public float getWidth();
/**
- * Sets the width of the object. Negative number implies unspecified size
- * (terminal is free to set the size).
- *
- * @param width
- * the width of the object in units specified by widthUnits
- * property.
- * @deprecated Consider using {@link #setWidth(String)} instead. This method
- * works, but is error-prone since the unit must be set
- * separately (and components might have different default
- * unit).
- */
- @Deprecated
- public void setWidth(float width);
-
- /**
* Gets the height of the object. Negative number implies unspecified size
* (terminal is free to set the size).
*
@@ -116,57 +157,18 @@ public interface Sizeable extends Serializable {
public float getHeight();
/**
- * Sets the height of the object. Negative number implies unspecified size
- * (terminal is free to set the size).
- *
- * @param height
- * the height of the object in units specified by heightUnits
- * property.
- * @deprecated Consider using {@link #setHeight(String)} or
- * {@link #setHeight(float, int)} instead. This method works,
- * but is error-prone since the unit must be set separately (and
- * components might have different default unit).
- */
- @Deprecated
- public void setHeight(float height);
-
- /**
* Gets the width property units.
*
* @return units used in width property.
*/
- public int getWidthUnits();
-
- /**
- * Sets the width property units.
- *
- * @param units
- * the units used in width property.
- * @deprecated Consider setting width and unit simultaneously using
- * {@link #setWidth(String)} or {@link #setWidth(float, int)},
- * which is less error-prone.
- */
- @Deprecated
- public void setWidthUnits(int units);
+ public Unit getWidthUnits();
/**
* Gets the height property units.
*
* @return units used in height property.
*/
- public int getHeightUnits();
-
- /**
- * Sets the height property units.
- *
- * @param units
- * the units used in height property.
- * @deprecated Consider setting height and unit simultaneously using
- * {@link #setHeight(String)} or {@link #setHeight(float, int)},
- * which is less error-prone.
- */
- @Deprecated
- public void setHeightUnits(int units);
+ public Unit getHeightUnits();
/**
* Sets the height of the component using String presentation.
@@ -193,13 +195,9 @@ public interface Sizeable extends Serializable {
* @param width
* the width of the object.
* @param unit
- * the unit used for the width. Possible values include
- * {@link #UNITS_PIXELS}, {@link #UNITS_POINTS},
- * {@link #UNITS_PICAS}, {@link #UNITS_EM}, {@link #UNITS_EX},
- * {@link #UNITS_MM}, {@link #UNITS_CM}, {@link #UNITS_INCH},
- * {@link #UNITS_PERCENTAGE}.
+ * the unit used for the width.
*/
- public void setWidth(float width, int unit);
+ public void setWidth(float width, Unit unit);
/**
* Sets the height of the object. Negative number implies unspecified size
@@ -208,13 +206,9 @@ public interface Sizeable extends Serializable {
* @param height
* the height of the object.
* @param unit
- * the unit used for the width. Possible values include
- * {@link #UNITS_PIXELS}, {@link #UNITS_POINTS},
- * {@link #UNITS_PICAS}, {@link #UNITS_EM}, {@link #UNITS_EX},
- * {@link #UNITS_MM}, {@link #UNITS_CM}, {@link #UNITS_INCH},
- * {@link #UNITS_PERCENTAGE}.
+ * the unit used for the width.
*/
- public void setHeight(float height, int unit);
+ public void setHeight(float height, Unit unit);
/**
* Sets the width of the component using String presentation.
diff --git a/src/com/vaadin/terminal/SystemError.java b/src/com/vaadin/terminal/SystemError.java
index ce1483dbb5..7f2464c9b9 100644
--- a/src/com/vaadin/terminal/SystemError.java
+++ b/src/com/vaadin/terminal/SystemError.java
@@ -69,8 +69,8 @@ public class SystemError extends RuntimeException implements ErrorMessage {
/**
* @see com.vaadin.terminal.ErrorMessage#getErrorLevel()
*/
- public final int getErrorLevel() {
- return ErrorMessage.SYSTEMERROR;
+ public final ErrorLevel getErrorLevel() {
+ return ErrorLevel.SYSTEMERROR;
}
/**
@@ -79,7 +79,7 @@ public class SystemError extends RuntimeException implements ErrorMessage {
public void paint(PaintTarget target) throws PaintException {
target.startTag("error");
- target.addAttribute("level", "system");
+ target.addAttribute("level", ErrorLevel.SYSTEMERROR.getText());
String message = getHtmlMessage();
diff --git a/src/com/vaadin/terminal/URIHandler.java b/src/com/vaadin/terminal/URIHandler.java
deleted file mode 100644
index b3fea0e3bf..0000000000
--- a/src/com/vaadin/terminal/URIHandler.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal;
-
-import java.io.Serializable;
-import java.net.URL;
-
-/**
- * A URIHandler is used for handling URI:s requested by the user and can
- * optionally provide a {@link DownloadStream}. If a {@link DownloadStream} is
- * returned by {@link #handleURI(URL, String)}, the stream is sent to the
- * client.
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public interface URIHandler extends Serializable {
-
- /**
- * Handles a given URI. If the URI handler to emit a downloadable stream it
- * should return a {@code DownloadStream} object.
- *
- * @param context
- * the base URL
- * @param relativeUri
- * a URI relative to {@code context}
- * @return A downloadable stream or null if no stream is provided
- */
- public DownloadStream handleURI(URL context, String relativeUri);
-
- /**
- * An {@code ErrorEvent} implementation for URIHandler.
- */
- public interface ErrorEvent extends Terminal.ErrorEvent {
-
- /**
- * Gets the URIHandler that caused this error.
- *
- * @return the URIHandler that caused the error
- */
- public URIHandler getURIHandler();
-
- }
-}
diff --git a/src/com/vaadin/terminal/UserError.java b/src/com/vaadin/terminal/UserError.java
index 170d76610b..8ec45ac725 100644
--- a/src/com/vaadin/terminal/UserError.java
+++ b/src/com/vaadin/terminal/UserError.java
@@ -18,31 +18,54 @@ import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;
@SuppressWarnings("serial")
public class UserError implements ErrorMessage {
+ public enum ContentMode {
+ /**
+ * Content mode, where the error contains only plain text.
+ */
+ TEXT,
+ /**
+ * Content mode, where the error contains preformatted text.
+ */
+ PREFORMATTED,
+ /**
+ * Formatted content mode, where the contents is XML restricted to the
+ * UIDL 1.0 formatting markups.
+ */
+ UIDL,
+ /**
+ * Content mode, where the error contains XHTML.
+ */
+ XHTML;
+ }
+
/**
- * Content mode, where the error contains only plain text.
+ * @deprecated from 7.0, use {@link ContentMode#TEXT} instead    
*/
- public static final int CONTENT_TEXT = 0;
+ @Deprecated
+ public static final ContentMode CONTENT_TEXT = ContentMode.TEXT;
/**
- * Content mode, where the error contains preformatted text.
+ * @deprecated from 7.0, use {@link ContentMode#PREFORMATTED} instead    
*/
- public static final int CONTENT_PREFORMATTED = 1;
+ @Deprecated
+ public static final ContentMode CONTENT_PREFORMATTED = ContentMode.PREFORMATTED;
/**
- * Formatted content mode, where the contents is XML restricted to the UIDL
- * 1.0 formatting markups.
+ * @deprecated from 7.0, use {@link ContentMode#UIDL} instead    
*/
- public static final int CONTENT_UIDL = 2;
+ @Deprecated
+ public static final ContentMode CONTENT_UIDL = ContentMode.UIDL;
/**
- * Content mode, where the error contains XHTML.
+ * @deprecated from 7.0, use {@link ContentMode#XHTML} instead    
*/
- public static final int CONTENT_XHTML = 3;
+ @Deprecated
+ public static final ContentMode CONTENT_XHTML = ContentMode.XHTML;
/**
* Content mode.
*/
- private int mode = CONTENT_TEXT;
+ private ContentMode mode = ContentMode.TEXT;
/**
* Message in content mode.
@@ -52,7 +75,7 @@ public class UserError implements ErrorMessage {
/**
* Error level.
*/
- private int level = ErrorMessage.ERROR;
+ private ErrorLevel level = ErrorLevel.ERROR;
/**
* Creates a textual error message of level ERROR.
@@ -64,31 +87,21 @@ public class UserError implements ErrorMessage {
msg = textErrorMessage;
}
- /**
- * Creates a error message with level and content mode.
- *
- * @param message
- * the error message.
- * @param contentMode
- * the content Mode.
- * @param errorLevel
- * the level of error.
- */
- public UserError(String message, int contentMode, int errorLevel) {
-
- // Check the parameters
- if (contentMode < 0 || contentMode > 2) {
- throw new java.lang.IllegalArgumentException(
- "Unsupported content mode: " + contentMode);
+ public UserError(String message, ContentMode contentMode,
+ ErrorLevel errorLevel) {
+ if (contentMode == null) {
+ contentMode = ContentMode.TEXT;
+ }
+ if (errorLevel == null) {
+ errorLevel = ErrorLevel.ERROR;
}
-
msg = message;
mode = contentMode;
level = errorLevel;
}
/* Documented in interface */
- public int getErrorLevel() {
+ public ErrorLevel getErrorLevel() {
return level;
}
@@ -108,38 +121,25 @@ public class UserError implements ErrorMessage {
public void paint(PaintTarget target) throws PaintException {
target.startTag("error");
-
- // Error level
- if (level >= ErrorMessage.SYSTEMERROR) {
- target.addAttribute("level", "system");
- } else if (level >= ErrorMessage.CRITICAL) {
- target.addAttribute("level", "critical");
- } else if (level >= ErrorMessage.ERROR) {
- target.addAttribute("level", "error");
- } else if (level >= ErrorMessage.WARNING) {
- target.addAttribute("level", "warning");
- } else {
- target.addAttribute("level", "info");
- }
+ target.addAttribute("level", level.getText());
// Paint the message
switch (mode) {
- case CONTENT_TEXT:
+ case TEXT:
target.addText(AbstractApplicationServlet.safeEscapeForHtml(msg));
break;
- case CONTENT_UIDL:
+ case UIDL:
target.addUIDL(msg);
break;
- case CONTENT_PREFORMATTED:
+ case PREFORMATTED:
target.addText("<pre>"
+ AbstractApplicationServlet.safeEscapeForHtml(msg)
+ "</pre>");
break;
- case CONTENT_XHTML:
+ case XHTML:
target.addText(msg);
break;
}
-
target.endTag("error");
}
diff --git a/src/com/vaadin/terminal/WrappedRequest.java b/src/com/vaadin/terminal/WrappedRequest.java
new file mode 100644
index 0000000000..a27213d921
--- /dev/null
+++ b/src/com/vaadin/terminal/WrappedRequest.java
@@ -0,0 +1,277 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.portlet.PortletRequest;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import com.vaadin.Application;
+import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.annotations.EagerInit;
+import com.vaadin.terminal.gwt.server.WebBrowser;
+import com.vaadin.ui.Root;
+
+/**
+ * A generic request to the server, wrapping a more specific request type, e.g.
+ * HttpServletReqest or PortletRequest.
+ *
+ * @since 7.0
+ */
+public interface WrappedRequest extends Serializable {
+
+ /**
+ * Detailed information extracted from the browser.
+ *
+ * @see WrappedRequest#getBrowserDetails()
+ */
+ public interface BrowserDetails extends Serializable {
+ /**
+ * Gets the URI hash fragment for the request. This is typically used to
+ * encode navigation within an application.
+ *
+ * @return the URI hash fragment
+ */
+ public String getUriFragment();
+
+ /**
+ * Gets the value of window.name from the browser. This can be used to
+ * keep track of the specific window between browser reloads.
+ *
+ * @return the string value of window.name in the browser
+ */
+ public String getWindowName();
+
+ /**
+ * Gets a reference to the {@link WebBrowser} object containing
+ * additional information, e.g. screen size and the time zone offset.
+ *
+ * @return the web browser object
+ */
+ public WebBrowser getWebBrowser();
+ }
+
+ /**
+ * Gets the named request parameter This is typically a HTTP GET or POST
+ * parameter, though other request types might have other ways of
+ * representing parameters.
+ *
+ * @see javax.servlet.ServletRequest#getParameter(String)
+ * @see javax.portlet.PortletRequest#getParameter(String)
+ *
+ * @param parameter
+ * the name of the parameter
+ * @return The paramter value, or <code>null</code> if no parameter with the
+ * given name is present
+ */
+ public String getParameter(String parameter);
+
+ /**
+ * Gets all the parameters of the request.
+ *
+ * @see #getParameter(String)
+ *
+ * @see javax.servlet.ServletRequest#getParameterMap()
+ * @see javax.portlet.PortletRequest#getParameter(String)
+ *
+ * @return A mapping of parameter names to arrays of parameter values
+ */
+ public Map<String, String[]> getParameterMap();
+
+ /**
+ * Returns the length of the request content that can be read from the input
+ * stream returned by {@link #getInputStream()}.
+ *
+ * @see javax.servlet.ServletRequest#getContentLength()
+ * @see javax.portlet.ClientDataRequest#getContentLength()
+ *
+ * @return content length in bytes
+ */
+ public int getContentLength();
+
+ /**
+ * Returns an input stream from which the request content can be read. The
+ * request content length can be obtained with {@link #getContentLength()}
+ * without reading the full stream contents.
+ *
+ * @see javax.servlet.ServletRequest#getInputStream()
+ * @see javax.portlet.ClientDataRequest#getPortletInputStream()
+ *
+ * @return the input stream from which the contents of the request can be
+ * read
+ * @throws IOException
+ * if the input stream can not be opened
+ */
+ public InputStream getInputStream() throws IOException;
+
+ /**
+ * Gets a request attribute.
+ *
+ * @param name
+ * the name of the attribute
+ * @return the value of the attribute, or <code>null</code> if there is no
+ * attribute with the given name
+ *
+ * @see javax.servlet.ServletRequest#getAttribute(String)
+ * @see javax.portlet.PortletRequest#getAttribute(String)
+ */
+ public Object getAttribute(String name);
+
+ /**
+ * Defines a request attribute.
+ *
+ * @param name
+ * the name of the attribute
+ * @param value
+ * the attribute value
+ *
+ * @see javax.servlet.ServletRequest#setAttribute(String, Object)
+ * @see javax.portlet.PortletRequest#setAttribute(String, Object)
+ */
+ public void setAttribute(String name, Object value);
+
+ /**
+ * Gets the path of the requested resource relative to the application. The
+ * path be <code>null</code> if no path information is available. Does
+ * always start with / if the path isn't <code>null</code>.
+ *
+ * @return a string with the path relative to the application.
+ *
+ * @see javax.servlet.http.HttpServletRequest#getPathInfo()
+ */
+ public String getRequestPathInfo();
+
+ /**
+ * Returns the maximum time interval, in seconds, that the session
+ * associated with this request will be kept open between client accesses.
+ *
+ * @return an integer specifying the number of seconds the session
+ * associated with this request remains open between client requests
+ *
+ * @see javax.servlet.http.HttpSession#getMaxInactiveInterval()
+ * @see javax.portlet.PortletSession#getMaxInactiveInterval()
+ */
+ public int getSessionMaxInactiveInterval();
+
+ /**
+ * Gets an attribute from the session associated with this request.
+ *
+ * @param name
+ * the name of the attribute
+ * @return the attribute value, or <code>null</code> if the attribute is not
+ * defined in the session
+ *
+ * @see javax.servlet.http.HttpSession#getAttribute(String)
+ * @see javax.portlet.PortletSession#getAttribute(String)
+ */
+ public Object getSessionAttribute(String name);
+
+ /**
+ * Saves an attribute value in the session associated with this request.
+ *
+ * @param name
+ * the name of the attribute
+ * @param attribute
+ * the attribute value
+ *
+ * @see javax.servlet.http.HttpSession#setAttribute(String, Object)
+ * @see javax.portlet.PortletSession#setAttribute(String, Object)
+ */
+ public void setSessionAttribute(String name, Object attribute);
+
+ /**
+ * Returns the MIME type of the body of the request, or null if the type is
+ * not known.
+ *
+ * @return a string containing the name of the MIME type of the request, or
+ * null if the type is not known
+ *
+ * @see javax.servlet.ServletRequest#getContentType()
+ * @see javax.portlet.ResourceRequest#getContentType()
+ *
+ */
+ public String getContentType();
+
+ /**
+ * Gets detailed information about the browser from which the request
+ * originated. This consists of information that is not available from
+ * normal HTTP requests, but requires additional information to be extracted
+ * for instance using javascript in the browser.
+ *
+ * This information is only guaranteed to be available in some special
+ * cases, for instance when {@link Application#getRoot} is called again
+ * after throwing {@link RootRequiresMoreInformationException} or in
+ * {@link Root#init(WrappedRequest)} for a Root class not annotated with
+ * {@link EagerInit}
+ *
+ * @return the browser details, or <code>null</code> if details are not
+ * available
+ *
+ * @see BrowserDetails
+ */
+ public BrowserDetails getBrowserDetails();
+
+ /**
+ * Gets locale information from the query, e.g. using the Accept-Language
+ * header.
+ *
+ * @return the preferred Locale
+ *
+ * @see ServletRequest#getLocale()
+ * @see PortletRequest#getLocale()
+ */
+ public Locale getLocale();
+
+ /**
+ * Returns the IP address from which the request came. This might also be
+ * the address of a proxy between the server and the original requester.
+ *
+ * @return a string containing the IP address, or <code>null</code> if the
+ * address is not available
+ *
+ * @see ServletRequest#getRemoteAddr()
+ */
+ public String getRemoteAddr();
+
+ /**
+ * Checks whether the request was made using a secure channel, e.g. using
+ * https.
+ *
+ * @return a boolean indicating if the request is secure
+ *
+ * @see ServletRequest#isSecure()
+ * @see PortletRequest#isSecure()
+ */
+ public boolean isSecure();
+
+ /**
+ * Gets the value of a request header, e.g. a http header for a
+ * {@link HttpServletRequest}.
+ *
+ * @param headerName
+ * the name of the header
+ * @return the header value, or <code>null</code> if the header is not
+ * present in the request
+ *
+ * @see HttpServletRequest#getHeader(String)
+ */
+ public String getHeader(String headerName);
+
+ /**
+ * Gets the deployment configuration for the context of this request.
+ *
+ * @return the deployment configuration
+ *
+ * @see DeploymentConfiguration
+ */
+ public DeploymentConfiguration getDeploymentConfiguration();
+
+}
diff --git a/src/com/vaadin/terminal/WrappedResponse.java b/src/com/vaadin/terminal/WrappedResponse.java
new file mode 100644
index 0000000000..995133a269
--- /dev/null
+++ b/src/com/vaadin/terminal/WrappedResponse.java
@@ -0,0 +1,147 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+
+import javax.portlet.MimeResponse;
+import javax.portlet.PortletResponse;
+import javax.portlet.ResourceResponse;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A generic response from the server, wrapping a more specific response type,
+ * e.g. HttpServletResponse or PortletResponse.
+ *
+ * @since 7.0
+ */
+public interface WrappedResponse extends Serializable {
+
+ /**
+ * Sets the (http) status code for the response. If you want to include an
+ * error message along the status code, use {@link #sendError(int, String)}
+ * instead.
+ *
+ * @param statusCode
+ * the status code to set
+ * @see HttpServletResponse#setStatus(int)
+ *
+ * @see ResourceResponse#HTTP_STATUS_CODE
+ */
+ public void setStatus(int statusCode);
+
+ /**
+ * Sets the content type of this response. If the content type including a
+ * charset is set before {@link #getWriter()} is invoked, the returned
+ * PrintWriter will automatically use the defined charset.
+ *
+ * @param contentType
+ * a string specifying the MIME type of the content
+ *
+ * @see ServletResponse#setContentType(String)
+ * @see MimeResponse#setContentType(String)
+ */
+ public void setContentType(String contentType);
+
+ /**
+ * Sets the value of a generic response header. If the header had already
+ * been set, the new value overwrites the previous one.
+ *
+ * @param name
+ * the name of the header
+ * @param value
+ * the header value.
+ *
+ * @see HttpServletResponse#setHeader(String, String)
+ * @see PortletResponse#setProperty(String, String)
+ */
+ public void setHeader(String name, String value);
+
+ /**
+ * Properly formats a timestamp as a date header. If the header had already
+ * been set, the new value overwrites the previous one.
+ *
+ * @param name
+ * the name of the header
+ * @param timestamp
+ * the number of milliseconds since epoch
+ *
+ * @see HttpServletResponse#setDateHeader(String, long)
+ */
+ public void setDateHeader(String name, long timestamp);
+
+ /**
+ * Returns a <code>OutputStream</code> for writing binary data in the
+ * response.
+ * <p>
+ * Either this method or getWriter() may be called to write the response,
+ * not both.
+ *
+ * @return a <code>OutputStream</code> for writing binary data
+ * @throws IOException
+ * if an input or output exception occurred
+ *
+ * @see #getWriter()
+ * @see ServletResponse#getOutputStream()
+ * @see MimeResponse#getPortletOutputStream()
+ */
+ public OutputStream getOutputStream() throws IOException;
+
+ /**
+ * Returns a <code>PrintWriter</code> object that can send character text to
+ * the client. The PrintWriter uses the character encoding defined using
+ * setContentType.
+ * <p>
+ * Either this method or getOutputStream() may be called to write the
+ * response, not both.
+ *
+ * @return a <code>PrintWriter</code> for writing character text
+ * @throws IOException
+ * if an input or output exception occurred
+ *
+ * @see #getOutputStream()
+ * @see ServletResponse#getWriter()
+ * @see MimeResponse#getWriter()
+ */
+ public PrintWriter getWriter() throws IOException;
+
+ /**
+ * Sets cache time in milliseconds, -1 means no cache at all. All required
+ * headers related to caching in the response are set based on the time.
+ *
+ * @param milliseconds
+ * Cache time in milliseconds
+ */
+ public void setCacheTime(long milliseconds);
+
+ /**
+ * Sends an error response to the client using the specified status code and
+ * clears the buffer. In some configurations, this can cause a predefined
+ * error page to be displayed.
+ *
+ * @param errorCode
+ * the HTTP status code
+ * @param message
+ * a message to accompany the error
+ * @throws IOException
+ * if an input or output exception occurs
+ *
+ * @see HttpServletResponse#sendError(int, String)
+ */
+ public void sendError(int errorCode, String message) throws IOException;
+
+ /**
+ * Gets the deployment configuration for the context of this response.
+ *
+ * @return the deployment configuration
+ *
+ * @see DeploymentConfiguration
+ */
+ public DeploymentConfiguration getDeploymentConfiguration();
+}
diff --git a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
index 7844ccecf1..9bc05dee2e 100644
--- a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
+++ b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
@@ -22,14 +22,8 @@
<when-type-is class="com.vaadin.terminal.gwt.client.Console" />
</replace-with>
- <!-- Use our own history impl for IE to workaround #2931. -->
- <replace-with class="com.vaadin.terminal.gwt.client.HistoryImplIEVaadin">
- <when-type-is class="com.google.gwt.user.client.impl.HistoryImpl" />
- <when-property-is name="user.agent" value="ie6" />
- </replace-with>
-
<generate-with
- class="com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator">
+ class="com.vaadin.terminal.gwt.widgetsetutils.WidgetMapGenerator">
<when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap" />
</generate-with>
@@ -61,7 +55,6 @@
<when-type-is
class="com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper" />
<any>
- <when-property-is name="user.agent" value="ie6" />
<when-property-is name="user.agent" value="ie8" />
</any>
</replace-with>
@@ -73,6 +66,9 @@
</replace-with>
<entry-point class="com.vaadin.terminal.gwt.client.ApplicationConfiguration" />
+
+ <!-- Use the new cross site linker to get a nocache.js without document.write -->
+ <add-linker name="xsiframe" />
</module>
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
index 5782a0b822..fbf1b2c2d6 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
@@ -5,7 +5,6 @@ package com.vaadin.terminal.gwt.client;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -14,13 +13,171 @@ import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
-import com.vaadin.terminal.gwt.client.ui.VUnknownComponent;
+import com.vaadin.terminal.gwt.client.ui.VUnknownComponentPaintable;
public class ApplicationConfiguration implements EntryPoint {
/**
+ * Helper class for reading configuration options from the bootstap
+ * javascript
+ *
+ * @since 7.0
+ */
+ private static class JsoConfiguration extends JavaScriptObject {
+ protected JsoConfiguration() {
+ // JSO Constructor
+ }
+
+ /**
+ * Reads a configuration parameter as a string. Please note that the
+ * javascript value of the parameter should also be a string, or else an
+ * undefined exception may be thrown.
+ *
+ * @param name
+ * name of the configuration parameter
+ * @return value of the configuration parameter, or <code>null</code> if
+ * not defined
+ */
+ private native String getConfigString(String name)
+ /*-{
+ var value = this.getConfig(name);
+ if (value === null || value === undefined) {
+ return null;
+ } else {
+ return value +"";
+ }
+ }-*/;
+
+ /**
+ * Reads a configuration parameter as a boolean object. Please note that
+ * the javascript value of the parameter should also be a boolean, or
+ * else an undefined exception may be thrown.
+ *
+ * @param name
+ * name of the configuration parameter
+ * @return boolean value of the configuration paramter, or
+ * <code>null</code> if no value is defined
+ */
+ private native Boolean getConfigBoolean(String name)
+ /*-{
+ var value = this.getConfig(name);
+ if (value === null || value === undefined) {
+ return null;
+ } else {
+ return @java.lang.Boolean::valueOf(Z)(value);
+ }
+ }-*/;
+
+ /**
+ * Reads a configuration parameter as an integer object. Please note
+ * that the javascript value of the parameter should also be an integer,
+ * or else an undefined exception may be thrown.
+ *
+ * @param name
+ * name of the configuration parameter
+ * @return integer value of the configuration paramter, or
+ * <code>null</code> if no value is defined
+ */
+ private native Integer getConfigInteger(String name)
+ /*-{
+ var value = this.getConfig(name);
+ if (value === null || value === undefined) {
+ return null;
+ } else {
+ return @java.lang.Integer::valueOf(I)(value);
+ }
+ }-*/;
+
+ /**
+ * Reads a configuration parameter as an {@link ErrorMessage} object.
+ * Please note that the javascript value of the parameter should also be
+ * an object with appropriate fields, or else an undefined exception may
+ * be thrown when calling this method or when calling methods on the
+ * returned object.
+ *
+ * @param name
+ * name of the configuration parameter
+ * @return error message with the given name, or <code>null</code> if no
+ * value is defined
+ */
+ private native ErrorMessage getConfigError(String name)
+ /*-{
+ return this.getConfig(name);
+ }-*/;
+
+ /**
+ * Returns a native javascript object containing version information
+ * from the server.
+ *
+ * @return a javascript object with the version information
+ */
+ private native JavaScriptObject getVersionInfoJSObject()
+ /*-{
+ return this.getConfig("versionInfo");
+ }-*/;
+
+ /**
+ * Gets the version of the Vaadin framework used on the server.
+ *
+ * @return a string with the version
+ *
+ * @see com.vaadin.terminal.gwt.server.AbstractApplicationServlet#VERSION
+ */
+ private native String getVaadinVersion()
+ /*-{
+ return this.getConfig("versionInfo").vaadinVersion;
+ }-*/;
+
+ /**
+ * Gets the version of the application running on the server.
+ *
+ * @return a string with the application version
+ *
+ * @see com.vaadin.Application#getVersion()
+ */
+ private native String getApplicationVersion()
+ /*-{
+ return this.getConfig("versionInfo").applicationVersion;
+ }-*/;
+
+ private native String getUIDL()
+ /*-{
+ return this.getConfig("uidl");
+ }-*/;
+ }
+
+ /**
+ * Wraps a native javascript object containing fields for an error message
+ *
+ * @since 7.0
+ */
+ public static final class ErrorMessage extends JavaScriptObject {
+
+ protected ErrorMessage() {
+ // JSO constructor
+ }
+
+ public final native String getCaption()
+ /*-{
+ return this.caption;
+ }-*/;
+
+ public final native String getMessage()
+ /*-{
+ return this.message;
+ }-*/;
+
+ public final native String getUrl()
+ /*-{
+ return this.url;
+ }-*/;
+ }
+
+ /**
* Builds number. For example 0-custom_tag in 5.0.0-custom_tag.
*/
public static final String VERSION;
@@ -39,32 +196,27 @@ public class ApplicationConfiguration implements EntryPoint {
private String id;
private String themeUri;
private String appUri;
- private JavaScriptObject versionInfo;
- private String windowName;
+ private int rootId;
private boolean standalone;
- private String communicationErrorCaption;
- private String communicationErrorMessage;
- private String communicationErrorUrl;
- private String authorizationErrorCaption;
- private String authorizationErrorMessage;
- private String authorizationErrorUrl;
- private String requiredWidgetset;
+ private ErrorMessage communicationError;
+ private ErrorMessage authorizationError;
private boolean useDebugIdInDom = true;
private boolean usePortletURLs = false;
private String portletUidlURLBase;
private HashMap<String, String> unknownComponents;
- private Class<? extends Paintable>[] classes = new Class[1024];
+ private Class<? extends VPaintableWidget>[] classes = new Class[1024];
private String windowId;
+ private boolean browserDetailsSent = false;
+
static// TODO consider to make this hashmap per application
LinkedList<Command> callbacks = new LinkedList<Command>();
private static int widgetsLoading;
- private static ArrayList<ApplicationConnection> unstartedApplications = new ArrayList<ApplicationConnection>();
private static ArrayList<ApplicationConnection> runningApplications = new ArrayList<ApplicationConnection>();
public boolean usePortletURLs() {
@@ -98,6 +250,16 @@ public class ApplicationConfiguration implements EntryPoint {
}
/**
+ * Gets the initial UIDL from the DOM, if it was provided during the init
+ * process.
+ *
+ * @return
+ */
+ public String getUIDL() {
+ return getJsoConfiguration(id).getUIDL();
+ }
+
+ /**
* @return true if the application is served by std. Vaadin servlet and is
* considered to be the only or main content of the host page.
*/
@@ -105,174 +267,99 @@ public class ApplicationConfiguration implements EntryPoint {
return standalone;
}
- public void setInitialWindowName(String name) {
- windowName = name;
- }
-
- public String getInitialWindowName() {
- return windowName;
+ /**
+ * Gets the root if of this application instance. The root id should be
+ * included in every request originating from this instance in order to
+ * associate it with the right Root instance on the server.
+ *
+ * @return the root id
+ */
+ public int getRootId() {
+ return rootId;
}
public JavaScriptObject getVersionInfoJSObject() {
- return versionInfo;
+ return getJsoConfiguration(id).getVersionInfoJSObject();
}
- public String getCommunicationErrorCaption() {
- return communicationErrorCaption;
+ public ErrorMessage getCommunicationError() {
+ return communicationError;
}
- public String getCommunicationErrorMessage() {
- return communicationErrorMessage;
+ public ErrorMessage getAuthorizationError() {
+ return authorizationError;
}
- public String getCommunicationErrorUrl() {
- return communicationErrorUrl;
- }
+ /**
+ * Reads the configuration values defined by the bootstrap javascript.
+ */
+ private void loadFromDOM() {
+ JsoConfiguration jsoConfiguration = getJsoConfiguration(id);
+ appUri = jsoConfiguration.getConfigString("appUri");
+ if (appUri != null && !appUri.endsWith("/")) {
+ appUri += '/';
+ }
+ themeUri = jsoConfiguration.getConfigString("themeUri");
+ rootId = jsoConfiguration.getConfigInteger("rootId").intValue();
- public String getAuthorizationErrorCaption() {
- return authorizationErrorCaption;
- }
+ // null -> true
+ useDebugIdInDom = jsoConfiguration.getConfigBoolean("useDebugIdInDom") != Boolean.FALSE;
- public String getAuthorizationErrorMessage() {
- return authorizationErrorMessage;
- }
+ // null -> false
+ usePortletURLs = jsoConfiguration.getConfigBoolean("usePortletURLs") == Boolean.TRUE;
- public String getAuthorizationErrorUrl() {
- return authorizationErrorUrl;
- }
+ portletUidlURLBase = jsoConfiguration
+ .getConfigString("portletUidlURLBase");
- public String getRequiredWidgetset() {
- return requiredWidgetset;
- }
+ // null -> false
+ standalone = jsoConfiguration.getConfigBoolean("standalone") == Boolean.TRUE;
- private native void loadFromDOM()
- /*-{
+ communicationError = jsoConfiguration.getConfigError("comErrMsg");
+ authorizationError = jsoConfiguration.getConfigError("authErrMsg");
- var id = this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::id;
- if($wnd.vaadin.vaadinConfigurations && $wnd.vaadin.vaadinConfigurations[id]) {
- var jsobj = $wnd.vaadin.vaadinConfigurations[id];
- var uri = jsobj.appUri;
- if(uri != null && uri[uri.length -1] != "/") {
- uri = uri + "/";
- }
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::appUri = uri;
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::themeUri = jsobj.themeUri;
- if(jsobj.windowName) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::windowName = jsobj.windowName;
- }
- if('useDebugIdInDom' in jsobj && typeof(jsobj.useDebugIdInDom) == "boolean") {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::useDebugIdInDom = jsobj.useDebugIdInDom;
- }
- if(jsobj.versionInfo) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::versionInfo = jsobj.versionInfo;
- }
- if(jsobj.comErrMsg) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::communicationErrorCaption = jsobj.comErrMsg.caption;
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::communicationErrorMessage = jsobj.comErrMsg.message;
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::communicationErrorUrl = jsobj.comErrMsg.url;
- }
- if(jsobj.authErrMsg) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::authorizationErrorCaption = jsobj.authErrMsg.caption;
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::authorizationErrorMessage = jsobj.authErrMsg.message;
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::authorizationErrorUrl = jsobj.authErrMsg.url;
- }
- if (jsobj.usePortletURLs) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::usePortletURLs = jsobj.usePortletURLs;
- }
- if (jsobj.portletUidlURLBase) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::portletUidlURLBase = jsobj.portletUidlURLBase;
- }
- if (jsobj.standalone) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::standalone = true;
- }
- if (jsobj.widgetset) {
- this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::requiredWidgetset = jsobj.widgetset;
- }
- } else {
- $wnd.alert("Vaadin app failed to initialize: " + this.id);
+ // boostrap sets initPending to false if it has sent the browser details
+ if (jsoConfiguration.getConfigBoolean("initPending") == Boolean.FALSE) {
+ setBrowserDetailsSent();
}
- }-*/;
+ }
/**
- * Inits the ApplicationConfiguration by reading the DOM and instantiating
- * ApplicationConnections accordingly. Call {@link #startNextApplication()}
- * to actually start the applications.
+ * Starts the application with a given id by reading the configuration
+ * options stored by the bootstrap javascript.
*
- * @param widgetset
- * the widgetset that is running the apps
+ * @param applicationId
+ * id of the application to load, this is also the id of the html
+ * element into which the application should be rendered.
*/
- public static void initConfigurations() {
-
- ArrayList<String> appIds = new ArrayList<String>();
- loadAppIdListFromDOM(appIds);
-
- for (Iterator<String> it = appIds.iterator(); it.hasNext();) {
- String appId = it.next();
- ApplicationConfiguration appConf = getConfigFromDOM(appId);
- if (canStartApplication(appConf)) {
+ public static void startApplication(final String applicationId) {
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ public void execute() {
+ ApplicationConfiguration appConf = getConfigFromDOM(applicationId);
ApplicationConnection a = GWT
.create(ApplicationConnection.class);
a.init(widgetSet, appConf);
- unstartedApplications.add(a);
- consumeApplication(appId);
- } else {
- VConsole.log("Application "
- + appId
- + " was not started. Provided widgetset did not match with this module.");
+ a.start();
+ runningApplications.add(a);
}
- }
-
+ });
}
- /**
- * Marks an applicatin with given id to be initialized. Suggesting other
- * modules should not try to start this application anymore.
- *
- * @param appId
- */
- private native static void consumeApplication(String appId)
- /*-{
- $wnd.vaadin.vaadinConfigurations[appId].initialized = true;
- }-*/;
-
- private static boolean canStartApplication(ApplicationConfiguration appConf) {
- return appConf.getRequiredWidgetset() == null
- || appConf.getRequiredWidgetset().equals(GWT.getModuleName());
+ public static List<ApplicationConnection> getRunningApplications() {
+ return runningApplications;
}
/**
- * Starts the next unstarted application. The WidgetSet should call this
- * once to start the first application; after that, each application should
- * call this once it has started. This ensures that the applications are
- * started synchronously, which is neccessary to avoid session-id problems.
+ * Gets the configuration object for a specific application from the
+ * bootstrap javascript.
*
- * @return true if an unstarted application was found
+ * @param appId
+ * the id of the application to get configuration data for
+ * @return a native javascript object containing the configuration data
*/
- public static boolean startNextApplication() {
- if (unstartedApplications.size() > 0) {
- ApplicationConnection a = unstartedApplications.remove(0);
- a.start();
- runningApplications.add(a);
- return true;
- } else {
- deferredWidgetLoader = new DeferredWidgetLoader();
- return false;
- }
- }
-
- public static List<ApplicationConnection> getRunningApplications() {
- return runningApplications;
- }
-
- private native static void loadAppIdListFromDOM(ArrayList<String> list)
+ private native static JsoConfiguration getJsoConfiguration(String appId)
/*-{
- var j;
- for(j in $wnd.vaadin.vaadinConfigurations) {
- if(!$wnd.vaadin.vaadinConfigurations[j].initialized) {
- list.@java.util.Collection::add(Ljava/lang/Object;)(j);
- }
- }
+ return $wnd.vaadin.getApp(appId);
}-*/;
public static ApplicationConfiguration getConfigFromDOM(String appId) {
@@ -282,27 +369,26 @@ public class ApplicationConfiguration implements EntryPoint {
return conf;
}
- public native String getServletVersion()
- /*-{
- return this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::versionInfo.vaadinVersion;
- }-*/;
+ public String getServletVersion() {
+ return getJsoConfiguration(id).getVaadinVersion();
+ }
- public native String getApplicationVersion()
- /*-{
- return this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::versionInfo.applicationVersion;
- }-*/;
+ public String getApplicationVersion() {
+ return getJsoConfiguration(id).getApplicationVersion();
+ }
public boolean useDebugIdInDOM() {
return useDebugIdInDom;
}
- public Class<? extends Paintable> getWidgetClassByEncodedTag(String tag) {
+ public Class<? extends VPaintableWidget> getWidgetClassByEncodedTag(
+ String tag) {
try {
int parseInt = Integer.parseInt(tag);
return classes[parseInt];
} catch (Exception e) {
// component was not present in mappings
- return VUnknownComponent.class;
+ return VUnknownComponentPaintable.class;
}
}
@@ -312,12 +398,12 @@ public class ApplicationConfiguration implements EntryPoint {
String key = keyArray.get(i).intern();
int value = valueMap.getInt(key);
classes[value] = widgetSet.getImplementationByClassName(key);
- if (classes[value] == VUnknownComponent.class) {
+ if (classes[value] == VUnknownComponentPaintable.class) {
if (unknownComponents == null) {
unknownComponents = new HashMap<String, String>();
}
unknownComponents.put("" + value, key);
- } else if (key == "com.vaadin.ui.Window") {
+ } else if (key == "com.vaadin.ui.Root") {
windowId = "" + value;
}
}
@@ -398,7 +484,7 @@ public class ApplicationConfiguration implements EntryPoint {
public void run() {
pending = false;
if (!isBusy()) {
- Class<? extends Paintable> nextType = getNextType();
+ Class<? extends VPaintableWidget> nextType = getNextType();
if (nextType == null) {
// ensured that all widgets are loaded
deferredWidgetLoader = null;
@@ -411,8 +497,8 @@ public class ApplicationConfiguration implements EntryPoint {
}
}
- private Class<? extends Paintable> getNextType() {
- Class<? extends Paintable>[] deferredLoadedWidgets = widgetSet
+ private Class<? extends VPaintableWidget> getNextType() {
+ Class<? extends VPaintableWidget>[] deferredLoadedWidgets = widgetSet
.getDeferredLoadedWidgets();
if (deferredLoadedWidgets.length <= nextWidgetIndex) {
return null;
@@ -443,10 +529,6 @@ public class ApplicationConfiguration implements EntryPoint {
public void onModuleLoad() {
- // Enable IE6 Background image caching
- if (BrowserInfo.get().isIE6()) {
- enableIE6BackgroundImageCache();
- }
// Prepare VConsole for debugging
if (isDebugMode()) {
Console console = GWT.create(Console.class);
@@ -476,21 +558,22 @@ public class ApplicationConfiguration implements EntryPoint {
}
});
- initConfigurations();
- startNextApplication();
+ registerCallback(GWT.getModuleName());
+ deferredWidgetLoader = new DeferredWidgetLoader();
}
- // From ImageSrcIE6
- private static native void enableIE6BackgroundImageCache()
+ /**
+ * Registers that callback that the bootstrap javascript uses to start
+ * applications once the widgetset is loaded and all required information is
+ * available
+ *
+ * @param widgetsetName
+ * the name of this widgetset
+ */
+ public native static void registerCallback(String widgetsetName)
/*-{
- // Fix IE background image refresh bug, present through IE6
- // see http://www.mister-pixel.com/#Content__state=is_that_simple
- // this only works with IE6 SP1+
- try {
- $doc.execCommand("BackgroundImageCache", false, true);
- } catch (e) {
- // ignore error on other browsers
- }
+ var callbackHandler = @com.vaadin.terminal.gwt.client.ApplicationConfiguration::startApplication(Ljava/lang/String;);
+ $wnd.vaadin.registerWidgetset(widgetsetName, callbackHandler);
}-*/;
/**
@@ -522,4 +605,25 @@ public class ApplicationConfiguration implements EntryPoint {
return re.test(uri);
}-*/;
+ /**
+ * Checks whether information from the web browser (e.g. uri fragment and
+ * screen size) has been sent to the server.
+ *
+ * @return <code>true</code> if browser information has already been sent
+ *
+ * @see ApplicationConnection#getNativeBrowserDetailsParameters(String)
+ */
+ public boolean isBrowserDetailsSent() {
+ return browserDetailsSent;
+ }
+
+ /**
+ * Registers that the browser details have been sent.
+ * {@link #isBrowserDetailsSent()} will return
+ * <code> after this method has been invoked.
+ */
+ public void setBrowserDetailsSent() {
+ browserDetailsSent = true;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 944d9b5974..5fde5ba04c 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -28,20 +28,23 @@ import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage;
import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
import com.vaadin.terminal.gwt.client.ui.Field;
+import com.vaadin.terminal.gwt.client.ui.VAbstractPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.VAbstractPaintableWidgetContainer;
import com.vaadin.terminal.gwt.client.ui.VContextMenu;
import com.vaadin.terminal.gwt.client.ui.VNotification;
import com.vaadin.terminal.gwt.client.ui.VNotification.HideEvent;
import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.terminal.gwt.client.ui.VViewPaintable;
import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager;
import com.vaadin.terminal.gwt.server.AbstractCommunicationManager;
@@ -52,10 +55,11 @@ import com.vaadin.terminal.gwt.server.AbstractCommunicationManager;
*
* Client-side widgets receive updates from the corresponding server-side
* components as calls to
- * {@link Paintable#updateFromUIDL(UIDL, ApplicationConnection)} (not to be
- * confused with the server side interface {@link com.vaadin.terminal.Paintable}
- * ). Any client-side changes (typically resulting from user actions) are sent
- * back to the server as variable changes (see {@link #updateVariable()}).
+ * {@link VPaintableWidget#updateFromUIDL(UIDL, ApplicationConnection)} (not to
+ * be confused with the server side interface
+ * {@link com.vaadin.terminal.Paintable} ). Any client-side changes (typically
+ * resulting from user actions) are sent back to the server as variable changes
+ * (see {@link #updateVariable()}).
*
* TODO document better
*
@@ -86,6 +90,11 @@ public class ApplicationConnection {
public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key";
/**
+ * Name of the parameter used to transmit root ids back and forth
+ */
+ public static final String ROOT_ID_PARAMETER = "rootId";
+
+ /**
* @deprecated use UIDL_SECURITY_TOKEN_ID instead
*/
@Deprecated
@@ -124,9 +133,6 @@ public class ApplicationConnection {
private final ArrayList<String> pendingVariables = new ArrayList<String>();
- private final ComponentDetailMap idToPaintableDetail = ComponentDetailMap
- .create();
-
private WidgetSet widgetSet;
private VContextMenu contextMenu = null;
@@ -136,12 +142,14 @@ public class ApplicationConnection {
private Timer loadTimer3;
private Element loadElement;
- private final VView view;
+ private final VViewPaintable view;
protected boolean applicationRunning = false;
private int activeRequests = 0;
+ protected boolean cssLoaded = false;
+
/** Parameters for this application connection loaded from the web-page */
private ApplicationConfiguration configuration;
@@ -154,18 +162,16 @@ public class ApplicationConnection {
/** redirectTimer scheduling interval in seconds */
private int sessionExpirationInterval;
- private ArrayList<Paintable> relativeSizeChanges = new ArrayList<Paintable>();;
- private ArrayList<Paintable> componentCaptionSizeChanges = new ArrayList<Paintable>();;
+ private ArrayList<VPaintableWidget> relativeSizeChanges = new ArrayList<VPaintableWidget>();
+ private ArrayList<Widget> componentCaptionSizeChanges = new ArrayList<Widget>();
private Date requestStartTime;
private boolean validatingLayouts = false;
- private Set<Paintable> zeroWidthComponents = null;
-
- private Set<Paintable> zeroHeightComponents = null;
+ private Set<VPaintableWidget> zeroWidthComponents = null;
- private Set<String> unregistryBag = new HashSet<String>();
+ private Set<VPaintableWidget> zeroHeightComponents = null;
public ApplicationConnection() {
view = GWT.create(VView.class);
@@ -186,7 +192,6 @@ public class ApplicationConnection {
this.widgetSet = widgetSet;
configuration = cnf;
- windowName = configuration.getInitialWindowName();
ComponentLocator componentLocator = new ComponentLocator(this);
@@ -209,10 +214,19 @@ public class ApplicationConnection {
* failed to start. This ensures that the applications are started in order,
* to avoid session-id problems.
*
- * @return
*/
public void start() {
- repaintAll();
+ String jsonText = configuration.getUIDL();
+ if (jsonText == null) {
+ // inital UIDL not in DOM, request later
+ repaintAll();
+ } else {
+ // Update counter so TestBench knows something is still going on
+ incrementActiveRequests();
+
+ // initial UIDL provided in DOM, continue as if returned by request
+ handleJSONText(jsonText);
+ }
}
private native void initializeTestbenchHooks(
@@ -238,10 +252,6 @@ public class ApplicationConnection {
return componentLocator.@com.vaadin.terminal.gwt.client.ComponentLocator::getPathForElement(Lcom/google/gwt/user/client/Element;)(element);
}
- if (!$wnd.vaadin.clients) {
- $wnd.vaadin.clients = {};
- }
-
$wnd.vaadin.clients[TTAppId] = client;
}-*/;
@@ -366,39 +376,48 @@ public class ApplicationConnection {
return (activeRequests > 0);
}
+ public void incrementActiveRequests() {
+ if (activeRequests < 0) {
+ activeRequests = 1;
+ } else {
+ activeRequests++;
+ }
+ }
+
+ public void decrementActiveRequests() {
+ if (activeRequests > 0) {
+ activeRequests--;
+ }
+ }
+
private String getRepaintAllParameters() {
// collect some client side data that will be sent to server on
// initial uidl request
- int clientHeight = Window.getClientHeight();
- int clientWidth = Window.getClientWidth();
- com.google.gwt.dom.client.Element pe = view.getElement()
- .getParentElement();
- int offsetHeight = pe.getOffsetHeight();
- int offsetWidth = pe.getOffsetWidth();
- int screenWidth = BrowserInfo.get().getScreenWidth();
- int screenHeight = BrowserInfo.get().getScreenHeight();
- int tzOffset = BrowserInfo.get().getTimezoneOffset();
- int rtzOffset = BrowserInfo.get().getRawTimezoneOffset();
- int dstDiff = BrowserInfo.get().getDSTSavings();
- boolean dstInEffect = BrowserInfo.get().isDSTInEffect();
- long curDate = BrowserInfo.get().getCurrentDate().getTime();
+ String nativeBootstrapParameters = getNativeBrowserDetailsParameters(getConfiguration()
+ .getRootPanelId());
String widgetsetVersion = ApplicationConfiguration.VERSION;
- String token = History.getToken();
-
// TODO figure out how client and view size could be used better on
// server. screen size can be accessed via Browser object, but other
// values currently only via transaction listener.
- String parameters = "repaintAll=1&" + "sh=" + screenHeight + "&sw="
- + screenWidth + "&cw=" + clientWidth + "&ch=" + clientHeight
- + "&vw=" + offsetWidth + "&vh=" + offsetHeight + "&fr=" + token
- + "&tzo=" + tzOffset + "&rtzo=" + rtzOffset + "&dstd="
- + dstDiff + "&dston=" + dstInEffect + "&curdate=" + curDate
- + "&wsver=" + widgetsetVersion
- + (BrowserInfo.get().isTouchDevice() ? "&td=1" : "");
+ String parameters = "repaintAll=1&" + nativeBootstrapParameters
+ + "&wsver=" + widgetsetVersion;
return parameters;
}
+ /**
+ * Gets the browser detail parameters that are sent by the bootstrap
+ * javascript for two-request initialization.
+ *
+ * @param parentElementId
+ * @return
+ */
+ private static native String getNativeBrowserDetailsParameters(
+ String parentElementId)
+ /*-{
+ return $wnd.vaadin.getBrowserDetailsParameters(parentElementId);
+ }-*/;
+
protected void repaintAll() {
String repainAllParameters = getRepaintAllParameters();
makeUidlRequest("", repainAllParameters, false);
@@ -419,9 +438,9 @@ public class ApplicationConnection {
*
* @param paintable
*/
- void highlightComponent(Paintable paintable) {
+ void highlightComponent(VPaintableWidget paintable) {
String params = getRepaintAllParameters() + "&highlightComponent="
- + getPid(paintable);
+ + paintableMap.getPid(paintable);
makeUidlRequest("", params, false);
}
@@ -455,9 +474,8 @@ public class ApplicationConnection {
if (extraParams != null && extraParams.length() > 0) {
uri = addGetParameters(uri, extraParams);
}
- if (windowName != null && windowName.length() > 0) {
- uri = addGetParameters(uri, "windowName=" + windowName);
- }
+ uri = addGetParameters(uri,
+ ROOT_ID_PARAMETER + "=" + configuration.getRootId());
doUidlRequest(uri, payload, forceSync);
@@ -481,10 +499,6 @@ public class ApplicationConnection {
public void onError(Request request, Throwable exception) {
showCommunicationError(exception.getMessage());
endRequest();
- if (!applicationRunning) {
- // start failed, let's try to start the next app
- ApplicationConfiguration.startNextApplication();
- }
}
public void onResponseReceived(Request request,
@@ -519,7 +533,7 @@ public class ApplicationConnection {
(new Timer() {
@Override
public void run() {
- activeRequests--;
+ decrementActiveRequests();
doUidlRequest(uri, payload, synchronous);
}
}).schedule(delay);
@@ -555,29 +569,10 @@ public class ApplicationConnection {
}
}
- final Date start = new Date();
// for(;;);[realjson]
final String jsonText = response.getText().substring(9,
response.getText().length() - 1);
- final ValueMap json;
- try {
- json = parseJSONResponse(jsonText);
- } catch (final Exception e) {
- endRequest();
- showCommunicationError(e.getMessage()
- + " - Original JSON-text:" + jsonText);
- return;
- }
-
- VConsole.log("JSON parsing took "
- + (new Date().getTime() - start.getTime()) + "ms");
- if (applicationRunning) {
- handleReceivedJSONMessage(start, jsonText, json);
- } else {
- applicationRunning = true;
- handleWhenCSSLoaded(jsonText, json);
- ApplicationConfiguration.startNextApplication();
- }
+ handleJSONText(jsonText);
}
};
@@ -602,6 +597,34 @@ public class ApplicationConnection {
}
/**
+ * Handles received UIDL JSON text, parsing it, and passing it on to the
+ * appropriate handlers, while logging timiing information.
+ *
+ * @param jsonText
+ */
+ private void handleJSONText(String jsonText) {
+ final Date start = new Date();
+ final ValueMap json;
+ try {
+ json = parseJSONResponse(jsonText);
+ } catch (final Exception e) {
+ endRequest();
+ showCommunicationError(e.getMessage() + " - Original JSON-text:"
+ + jsonText);
+ return;
+ }
+
+ VConsole.log("JSON parsing took "
+ + (new Date().getTime() - start.getTime()) + "ms");
+ if (applicationRunning) {
+ handleReceivedJSONMessage(start, jsonText, json);
+ } else {
+ applicationRunning = true;
+ handleWhenCSSLoaded(jsonText, json);
+ }
+ }
+
+ /**
* Sends an asynchronous UIDL request to the server using the given URI.
*
* @param uri
@@ -630,9 +653,7 @@ public class ApplicationConnection {
protected void handleWhenCSSLoaded(final String jsonText,
final ValueMap json) {
- int heightOfLoadElement = DOM.getElementPropertyInt(loadElement,
- "offsetHeight");
- if (heightOfLoadElement == 0 && cssWaits < MAX_CSS_WAITS) {
+ if (!isCSSLoaded() && cssWaits < MAX_CSS_WAITS) {
(new Timer() {
@Override
public void run() {
@@ -644,6 +665,7 @@ public class ApplicationConnection {
+ "(.v-loading-indicator height == 0)");
cssWaits++;
} else {
+ cssLoaded = true;
handleReceivedJSONMessage(new Date(), jsonText, json);
if (cssWaits >= MAX_CSS_WAITS) {
VConsole.error("CSS files may have not loaded properly.");
@@ -652,6 +674,17 @@ public class ApplicationConnection {
}
/**
+ * Checks whether or not the CSS is loaded. By default checks the size of
+ * the loading indicator element.
+ *
+ * @return
+ */
+ protected boolean isCSSLoaded() {
+ return cssLoaded
+ || DOM.getElementPropertyInt(loadElement, "offsetHeight") != 0;
+ }
+
+ /**
* Shows the communication error notification.
*
* @param details
@@ -659,9 +692,9 @@ public class ApplicationConnection {
*/
protected void showCommunicationError(String details) {
VConsole.error("Communication error: " + details);
- showError(details, configuration.getCommunicationErrorCaption(),
- configuration.getCommunicationErrorMessage(),
- configuration.getCommunicationErrorUrl());
+ ErrorMessage communicationError = configuration.getCommunicationError();
+ showError(details, communicationError.getCaption(),
+ communicationError.getMessage(), communicationError.getUrl());
}
/**
@@ -672,9 +705,9 @@ public class ApplicationConnection {
*/
protected void showAuthenticationError(String details) {
VConsole.error("Authentication error: " + details);
- showError(details, configuration.getAuthorizationErrorCaption(),
- configuration.getAuthorizationErrorMessage(),
- configuration.getAuthorizationErrorUrl());
+ ErrorMessage authorizationError = configuration.getAuthorizationError();
+ showError(details, authorizationError.getCaption(),
+ authorizationError.getMessage(), authorizationError.getUrl());
}
/**
@@ -715,7 +748,7 @@ public class ApplicationConnection {
}
protected void startRequest() {
- activeRequests++;
+ incrementActiveRequests();
requestStartTime = new Date();
// show initial throbber
if (loadTimer == null) {
@@ -743,11 +776,11 @@ public class ApplicationConnection {
checkForPendingVariableBursts();
runPostRequestHooks(configuration.getRootPanelId());
}
- activeRequests--;
+ decrementActiveRequests();
// deferring to avoid flickering
Scheduler.get().scheduleDeferred(new Command() {
public void execute() {
- if (activeRequests == 0) {
+ if (!hasActiveRequest()) {
hideLoadingIndicator();
}
}
@@ -783,7 +816,8 @@ public class ApplicationConnection {
for (int i = 1; i < variableBurst.size(); i += 2) {
String id = variableBurst.get(i);
id = id.substring(0, id.indexOf(VAR_FIELD_SEPARATOR));
- if (!idToPaintableDetail.containsKey(id) && !id.startsWith("DD")) {
+ if (!getPaintableMap().hasPaintable(id)
+ && !getPaintableMap().isDragAndDropPaintable(id)) {
// variable owner does not exist anymore
variableBurst.remove(i - 1);
variableBurst.remove(i - 1);
@@ -798,7 +832,8 @@ public class ApplicationConnection {
if (loadElement == null) {
loadElement = DOM.createDiv();
DOM.setStyleAttribute(loadElement, "position", "absolute");
- DOM.appendChild(view.getElement(), loadElement);
+ DOM.appendChild(view.getWidgetForPaintable().getElement(),
+ loadElement);
VConsole.log("inserting load indicator");
}
DOM.setElementProperty(loadElement, "className", "v-loading-indicator");
@@ -828,12 +863,14 @@ public class ApplicationConnection {
private void hideLoadingIndicator() {
if (loadTimer != null) {
loadTimer.cancel();
- if (loadTimer2 != null) {
- loadTimer2.cancel();
- loadTimer3.cancel();
- }
loadTimer = null;
}
+ if (loadTimer2 != null) {
+ loadTimer2.cancel();
+ loadTimer3.cancel();
+ loadTimer2 = null;
+ loadTimer3 = null;
+ }
if (loadElement != null) {
DOM.setStyleAttribute(loadElement, "display", "none");
}
@@ -937,12 +974,12 @@ public class ApplicationConnection {
meta = json.getValueMap("meta");
if (meta.containsKey("repaintAll")) {
repaintAll = true;
- view.clear();
- idToPaintableDetail.clear();
+ view.getWidgetForPaintable().clear();
+ getPaintableMap().clear();
if (meta.containsKey("invalidLayouts")) {
validatingLayouts = true;
- zeroWidthComponents = new HashSet<Paintable>();
- zeroHeightComponents = new HashSet<Paintable>();
+ zeroWidthComponents = new HashSet<VPaintableWidget>();
+ zeroHeightComponents = new HashSet<VPaintableWidget>();
}
}
if (meta.containsKey("timedRedirect")) {
@@ -966,7 +1003,7 @@ public class ApplicationConnection {
// Process changes
JsArray<ValueMap> changes = json.getJSValueMapArray("changes");
- ArrayList<Paintable> updatedWidgets = new ArrayList<Paintable>();
+ ArrayList<VPaintableWidget> updatedVPaintableWidgets = new ArrayList<VPaintableWidget>();
relativeSizeChanges.clear();
componentCaptionSizeChanges.clear();
@@ -976,16 +1013,12 @@ public class ApplicationConnection {
final UIDL change = changes.get(i).cast();
final UIDL uidl = change.getChildUIDL(0);
// TODO optimize
- final Paintable paintable = getPaintable(uidl.getId());
+ final VPaintableWidget paintable = (VPaintableWidget) paintableMap
+ .getPaintable(uidl.getId());
if (paintable != null) {
paintable.updateFromUIDL(uidl,
ApplicationConnection.this);
- // paintable may have changed during render to
- // another
- // implementation, use the new one for updated
- // widgets map
- updatedWidgets.add(idToPaintableDetail.get(
- uidl.getId()).getComponent());
+ updatedVPaintableWidgets.add(paintable);
} else {
if (!uidl.getTag().equals(
configuration.getEncodedWindowTag())) {
@@ -995,14 +1028,13 @@ public class ApplicationConnection {
+ uidl.getId() + ") rendered.");
} else {
String pid = uidl.getId();
- if (!idToPaintableDetail.containsKey(pid)) {
- registerPaintable(pid, view);
+ if (!paintableMap.hasPaintable(pid)) {
+ paintableMap.registerPaintable(pid, view);
}
// VView does not call updateComponent so we
// register any event listeners here
- ComponentDetail cd = idToPaintableDetail
- .get(pid);
- cd.registerEventListenersFromUIDL(uidl);
+ paintableMap.registerEventListenersFromUIDL(
+ pid, uidl);
// Finally allow VView to update itself
view.updateFromUIDL(uidl,
@@ -1021,22 +1053,20 @@ public class ApplicationConnection {
}
// Check which widgets' size has been updated
- Set<Paintable> sizeUpdatedWidgets = new HashSet<Paintable>();
+ Set<Widget> sizeUpdatedWidgets = new HashSet<Widget>();
- updatedWidgets.addAll(relativeSizeChanges);
+ updatedVPaintableWidgets.addAll(relativeSizeChanges);
sizeUpdatedWidgets.addAll(componentCaptionSizeChanges);
- for (Paintable paintable : updatedWidgets) {
- ComponentDetail detail = idToPaintableDetail
- .get(getPid(paintable));
- Widget widget = (Widget) paintable;
- Size oldSize = detail.getOffsetSize();
+ for (VPaintableWidget paintable : updatedVPaintableWidgets) {
+ Widget widget = paintable.getWidgetForPaintable();
+ Size oldSize = paintableMap.getOffsetSize(paintable);
Size newSize = new Size(widget.getOffsetWidth(),
widget.getOffsetHeight());
if (oldSize == null || !oldSize.equals(newSize)) {
- sizeUpdatedWidgets.add(paintable);
- detail.setOffsetSize(newSize);
+ sizeUpdatedWidgets.add(widget);
+ paintableMap.setOffsetSize(paintable, newSize);
}
}
@@ -1090,9 +1120,9 @@ public class ApplicationConnection {
* idToPaintableDetail is already cleanded at the start of
* the changeset handling, bypass cleanup.
*/
- unregistryBag.clear();
+ paintableMap.purgeUnregistryBag(false);
} else {
- purgeUnregistryBag();
+ paintableMap.purgeUnregistryBag(true);
}
// TODO build profiling for widget impl loading time
@@ -1102,8 +1132,7 @@ public class ApplicationConnection {
VConsole.log(" Processing time was "
+ String.valueOf(prosessingTime) + "ms for "
+ jsonText.length() + " characters of JSON");
- VConsole.log("Referenced paintables: "
- + idToPaintableDetail.size());
+ VConsole.log("Referenced paintables: " + paintableMap.size());
endRequest();
@@ -1112,22 +1141,6 @@ public class ApplicationConnection {
ApplicationConfiguration.runWhenWidgetsLoaded(c);
}
- /**
- * This method assures that all pending variable changes are sent to server.
- * Method uses synchronized xmlhttprequest and does not return before the
- * changes are sent. No UIDL updates are processed and thus UI is left in
- * inconsistent state. This method should be called only when closing
- * windows - normally sendPendingVariableChanges() should be used.
- */
- public void sendPendingVariableChangesSync() {
- if (applicationRunning) {
- pendingVariableBursts.add(pendingVariables);
- ArrayList<String> nextBurst = pendingVariableBursts.get(0);
- pendingVariableBursts.remove(0);
- buildAndSendVariableBurst(nextBurst, true);
- }
- }
-
// Redirect browser, null reloads current page
private static native void redirect(String url)
/*-{
@@ -1138,164 +1151,6 @@ public class ApplicationConnection {
}
}-*/;
- public void registerPaintable(String pid, Paintable paintable) {
- ComponentDetail componentDetail = new ComponentDetail(this, pid,
- paintable);
- idToPaintableDetail.put(pid, componentDetail);
- setPid(((Widget) paintable).getElement(), pid);
- }
-
- private native void setPid(Element el, String pid)
- /*-{
- el.tkPid = pid;
- }-*/;
-
- /**
- * Gets the paintableId for a specific paintable (a.k.a Vaadin Widget).
- * <p>
- * The paintableId is used in the UIDL to identify a specific widget
- * instance, effectively linking the widget with it's server side Component.
- * </p>
- *
- * @param paintable
- * the paintable who's id is needed
- * @return the id for the given paintable
- */
- public String getPid(Paintable paintable) {
- return getPid(((Widget) paintable).getElement());
- }
-
- /**
- * Gets the paintableId using a DOM element - the element should be the main
- * element for a paintable otherwise no id will be found. Use
- * {@link #getPid(Paintable)} instead whenever possible.
- *
- * @see #getPid(Paintable)
- * @param el
- * element of the paintable whose pid is desired
- * @return the pid of the element's paintable, if it's a paintable
- */
- public native String getPid(Element el)
- /*-{
- return el.tkPid;
- }-*/;
-
- /**
- * Gets the main element for the paintable with the given id. The revers of
- * {@link #getPid(Element)}.
- *
- * @param pid
- * the pid of the widget whose element is desired
- * @return the element for the paintable corresponding to the pid
- */
- public Element getElementByPid(String pid) {
- return ((Widget) getPaintable(pid)).getElement();
- }
-
- /**
- * Unregisters the given paintable; always use after removing a paintable.
- * This method does not remove the paintable from the DOM, but marks the
- * paintable so that ApplicationConnection may clean up its references to
- * it. Removing the widget from DOM is component containers responsibility.
- *
- * @param p
- * the paintable to remove
- */
- public void unregisterPaintable(Paintable p) {
-
- // add to unregistry que
-
- if (p == null) {
- VConsole.error("WARN: Trying to unregister null paintable");
- return;
- }
- String id = getPid(p);
- if (id == null) {
- /*
- * Uncomment the following to debug unregistring components. No
- * paintables with null id should end here. At least one exception
- * is our VScrollTableRow, that is hacked to fake it self as a
- * Paintable to build support for sizing easier.
- */
- // if (!(p instanceof VScrollTableRow)) {
- // VConsole.log("Trying to unregister Paintable not created by Application Connection.");
- // }
- if (p instanceof HasWidgets) {
- unregisterChildPaintables((HasWidgets) p);
- }
- } else {
- unregistryBag.add(id);
- if (p instanceof HasWidgets) {
- unregisterChildPaintables((HasWidgets) p);
- }
- }
- }
-
- private void purgeUnregistryBag() {
- for (String id : unregistryBag) {
- ComponentDetail componentDetail = idToPaintableDetail.get(id);
- if (componentDetail == null) {
- /*
- * this should never happen, but it does :-( See e.g.
- * com.vaadin.tests.components.accordion.RemoveTabs (with test
- * script)
- */
- VConsole.error("ApplicationConnetion tried to unregister component (id="
- + id
- + ") that is never registered (or already unregistered)");
- continue;
- }
- // check if can be cleaned
- Widget component = (Widget) componentDetail.getComponent();
- if (!component.isAttached()) {
- // clean reference from ac to paintable
- idToPaintableDetail.remove(id);
- }
- /*
- * else NOP : same component has been reattached to another parent
- * or replaced by another component implementation.
- */
- }
-
- unregistryBag.clear();
- }
-
- /**
- * Unregisters a paintable and all it's child paintables recursively. Use
- * when after removing a paintable that contains other paintables. Does not
- * unregister the given container itself. Does not actually remove the
- * paintable from the DOM.
- *
- * @see #unregisterPaintable(Paintable)
- * @param container
- */
- public void unregisterChildPaintables(HasWidgets container) {
- final Iterator<Widget> it = container.iterator();
- while (it.hasNext()) {
- final Widget w = it.next();
- if (w instanceof Paintable) {
- unregisterPaintable((Paintable) w);
- } else if (w instanceof HasWidgets) {
- unregisterChildPaintables((HasWidgets) w);
- }
- }
- }
-
- /**
- * Returns Paintable element by its id
- *
- * @param id
- * Paintable ID
- */
- public Paintable getPaintable(String id) {
- ComponentDetail componentDetail = idToPaintableDetail.get(id);
- if (componentDetail == null) {
- return null;
- } else {
- return componentDetail.getComponent();
- }
- }
-
private void addVariableToQueue(String paintableId, String variableName,
String encodedValue, boolean immediate, char type) {
final String id = paintableId + VAR_FIELD_SEPARATOR + variableName
@@ -1381,7 +1236,18 @@ public class ApplicationConnection {
req.append(VAR_BURST_SEPARATOR);
}
}
- makeUidlRequest(req.toString(), "", forceSync);
+
+ // Include the browser detail parameters if they aren't already sent
+ String extraParams;
+ if (!getConfiguration().isBrowserDetailsSent()) {
+ extraParams = getNativeBrowserDetailsParameters(getConfiguration()
+ .getRootPanelId());
+ getConfiguration().setBrowserDetailsSent();
+ } else {
+ extraParams = "";
+ }
+
+ makeUidlRequest(req.toString(), extraParams, forceSync);
}
private void makeUidlRequest(String string) {
@@ -1406,8 +1272,8 @@ public class ApplicationConnection {
* true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
- Paintable newValue, boolean immediate) {
- String pid = (newValue != null) ? getPid(newValue) : null;
+ VPaintable newValue, boolean immediate) {
+ String pid = paintableMap.getPid(newValue);
addVariableToQueue(paintableId, variableName, pid, immediate, 'p');
}
@@ -1567,7 +1433,7 @@ public class ApplicationConnection {
* the id of the paintable that owns the variable
* @param variableName
* the name of the variable
- * @param newValue
+ * @param map
* the new value to be sent
* @param immediate
* true if the update is to be sent as soon as possible
@@ -1584,7 +1450,7 @@ public class ApplicationConnection {
buf.append(escapeVariableValue(key));
buf.append(VAR_ARRAYITEM_SEPARATOR);
if (transportType == 'p') {
- buf.append(getPid((Paintable) value));
+ buf.append(paintableMap.getPid((VPaintable) value));
} else {
buf.append(escapeVariableValue(String.valueOf(value)));
}
@@ -1601,7 +1467,7 @@ public class ApplicationConnection {
private char getTransportType(Object value) {
if (value instanceof String) {
return 's';
- } else if (value instanceof Paintable) {
+ } else if (value instanceof VPaintableWidget) {
return 'p';
} else if (value instanceof Boolean) {
return 'b';
@@ -1685,7 +1551,7 @@ public class ApplicationConnection {
// first char tells the type in array
buf.append(transportType);
if (transportType == 'p') {
- buf.append(getPid((Paintable) value));
+ buf.append(paintableMap.getPid((VPaintable) value));
} else {
buf.append(escapeVariableValue(String.valueOf(value)));
}
@@ -1766,24 +1632,18 @@ public class ApplicationConnection {
*
* @return Returns true iff no further painting is needed by caller
*/
- public boolean updateComponent(Widget component, UIDL uidl,
+ @Deprecated
+ public boolean updateComponent(VPaintableWidget paintable, UIDL uidl,
boolean manageCaption) {
- String pid = getPid(component.getElement());
+ Widget component = paintable.getWidgetForPaintable();
+
+ String pid = paintableMap.getPid(paintable);
if (pid == null) {
VConsole.error("Trying to update an unregistered component: "
+ Util.getSimpleName(component));
return true;
}
- ComponentDetail componentDetail = idToPaintableDetail.get(pid);
-
- if (componentDetail == null) {
- VConsole.error("ComponentDetail not found for "
- + Util.getSimpleName(component) + " with PID " + pid
- + ". This should not happen.");
- return true;
- }
-
// If the server request that a cached instance should be used, do
// nothing
if (uidl.getBooleanAttribute("cached")) {
@@ -1792,7 +1652,7 @@ public class ApplicationConnection {
// register the listened events by the server-side to the event-handler
// of the component
- componentDetail.registerEventListenersFromUIDL(uidl);
+ paintableMap.registerEventListenersFromUIDL(pid, uidl);
// Visibility
boolean visible = !uidl.getBooleanAttribute("invisible");
@@ -1802,11 +1662,7 @@ public class ApplicationConnection {
// Changed invisibile <-> visible
if (wasVisible && manageCaption) {
// Must hide caption when component is hidden
- final Container parent = Util.getLayout(component);
- if (parent != null) {
- parent.updateCaption((Paintable) component, uidl);
- }
-
+ updateCaption(paintable, uidl);
}
}
@@ -1818,28 +1674,10 @@ public class ApplicationConnection {
if (!visible) {
// component is invisible, delete old size to notify parent, if
// later make visible
- componentDetail.setOffsetSize(null);
+ paintableMap.setOffsetSize(paintable, null);
return true;
}
- // Switch to correct implementation if needed
- if (!widgetSet.isCorrectImplementation(component, uidl, configuration)) {
- final Widget w = (Widget) widgetSet.createWidget(uidl,
- configuration);
- // deferred binding check TODO change isCorrectImplementation to use
- // stored detected class, making this innecessary
- if (w.getClass() != component.getClass()) {
- final Container parent = Util.getLayout(component);
- if (parent != null) {
- parent.replaceChildComponent(component, w);
- unregisterPaintable((Paintable) component);
- registerPaintable(uidl.getId(), (Paintable) w);
- ((Paintable) w).updateFromUIDL(uidl, this);
- return true;
- }
- }
- }
-
boolean enabled = !uidl.getBooleanAttribute("disabled");
if (uidl.hasAttribute("tabindex") && component instanceof Focusable) {
((Focusable) component).setTabIndex(uidl
@@ -1854,7 +1692,11 @@ public class ApplicationConnection {
fw.setEnabled(enabled);
}
- TooltipInfo tooltipInfo = componentDetail.getTooltipInfo(null);
+ // Style names
+ component.setStyleName(getStyleName(component.getStylePrimaryName(),
+ uidl, component instanceof Field));
+
+ TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(paintable, null);
// Update tooltip
if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) {
tooltipInfo
@@ -1863,6 +1705,11 @@ public class ApplicationConnection {
tooltipInfo.setTitle(null);
}
+ // Set captions
+ if (manageCaption) {
+ updateCaption(paintable, uidl);
+ }
+
// add error classname to components w/ error
if (uidl.hasAttribute(ATTRIBUTE_ERROR)) {
tooltipInfo.setErrorUidl(uidl.getErrors());
@@ -1870,27 +1717,22 @@ public class ApplicationConnection {
tooltipInfo.setErrorUidl(null);
}
- // Style names
- component.setStyleName(getStyleName(component.getStylePrimaryName(),
- uidl, component instanceof Field));
-
- // Set captions
- if (manageCaption) {
- final Container parent = Util.getLayout(component);
- if (parent != null) {
- parent.updateCaption((Paintable) component, uidl);
- }
- }
/*
* updateComponentSize need to be after caption update so caption can be
* taken into account
*/
- updateComponentSize(componentDetail, uidl);
+ updateComponentSize(paintable, uidl);
return false;
}
+ @Deprecated
+ private void updateCaption(VPaintableWidget paintable, UIDL uidl) {
+ VPaintableWidgetContainer parent = paintable.getParentPaintable();
+ parent.updateCaption(paintable, uidl);
+ }
+
/**
* Generates the style name for the widget based on the given primary style
* name (typically returned by Widget.getPrimaryStyleName()) and the UIDL.
@@ -1939,6 +1781,7 @@ public class ApplicationConnection {
styleBuf.append(MODIFIED_CLASSNAME);
}
+ // add error classname to components w/ error
if (uidl.hasAttribute(ATTRIBUTE_ERROR)) {
styleBuf.append(" ");
styleBuf.append(primaryStyleName);
@@ -1952,10 +1795,9 @@ public class ApplicationConnection {
}
return styleBuf.toString();
-
}
- private void updateComponentSize(ComponentDetail cd, UIDL uidl) {
+ private void updateComponentSize(VPaintableWidget paintable, UIDL uidl) {
String w = uidl.hasAttribute("width") ? uidl
.getStringAttribute("width") : "";
@@ -1970,20 +1812,22 @@ public class ApplicationConnection {
// One or both is relative
FloatSize relativeSize = new FloatSize(relativeWidth,
relativeHeight);
- if (cd.getRelativeSize() == null && cd.getOffsetSize() != null) {
+
+ if (paintableMap.getRelativeSize(paintable) == null
+ && paintableMap.getOffsetSize(paintable) != null) {
// The component has changed from absolute size to relative size
- relativeSizeChanges.add(cd.getComponent());
+ relativeSizeChanges.add(paintable);
}
- cd.setRelativeSize(relativeSize);
+ paintableMap.setRelativeSize(paintable, relativeSize);
} else if (relativeHeight < 0.0 && relativeWidth < 0.0) {
- if (cd.getRelativeSize() != null) {
+ if (paintableMap.getRelativeSize(paintable) != null) {
// The component has changed from relative size to absolute size
- relativeSizeChanges.add(cd.getComponent());
+ relativeSizeChanges.add(paintable);
}
- cd.setRelativeSize(null);
+ paintableMap.setRelativeSize(paintable, null);
}
- Widget component = (Widget) cd.getComponent();
+ Widget component = paintableMap.getWidget(paintable);
// Set absolute sizes
if (relativeHeight < 0.0) {
component.setHeight(h);
@@ -1995,7 +1839,7 @@ public class ApplicationConnection {
// Set relative sizes
if (relativeHeight >= 0.0 || relativeWidth >= 0.0) {
// One or both is relative
- handleComponentRelativeSize(cd);
+ handleComponentRelativeSize(paintable);
}
}
@@ -2027,9 +1871,11 @@ public class ApplicationConnection {
* development. Published to JavaScript.
*/
public void forceLayout() {
- Set<Paintable> set = new HashSet<Paintable>();
- for (ComponentDetail cd : idToPaintableDetail.values()) {
- set.add(cd.getComponent());
+ Set<Widget> set = new HashSet<Widget>();
+ for (VPaintable paintable : paintableMap.getPaintables()) {
+ if (paintable instanceof VPaintableWidget) {
+ set.add(((VPaintableWidget) paintable).getWidgetForPaintable());
+ }
}
Util.componentSizeUpdated(set);
}
@@ -2041,7 +1887,7 @@ public class ApplicationConnection {
while (childWidgets.hasNext()) {
final Widget child = childWidgets.next();
- if (child instanceof Paintable) {
+ if (getPaintableMap().isPaintable(child)) {
if (handleComponentRelativeSize(child)) {
/*
@@ -2072,31 +1918,33 @@ public class ApplicationConnection {
* @param child
* @return true if the child has a relative size
*/
- private boolean handleComponentRelativeSize(ComponentDetail cd) {
- if (cd == null) {
+ private boolean handleComponentRelativeSize(VPaintableWidget paintable) {
+ if (paintable == null) {
return false;
}
- boolean debugSizes = false;
+ boolean debugSizes = true;
- FloatSize relativeSize = cd.getRelativeSize();
+ FloatSize relativeSize = paintableMap.getRelativeSize(paintable);
if (relativeSize == null) {
return false;
}
- Widget widget = (Widget) cd.getComponent();
+ Widget widget = paintableMap.getWidget(paintable);
boolean horizontalScrollBar = false;
boolean verticalScrollBar = false;
- Container parent = Util.getLayout(widget);
+ VPaintableWidgetContainer parentPaintable = paintable
+ .getParentPaintable();
RenderSpace renderSpace;
// Parent-less components (like sub-windows) are relative to browser
// window.
- if (parent == null) {
+ if (parentPaintable == null) {
renderSpace = new RenderSpace(Window.getClientWidth(),
Window.getClientHeight());
} else {
- renderSpace = parent.getAllocatedSpace(widget);
+ renderSpace = ((Container) parentPaintable.getWidgetForPaintable())
+ .getAllocatedSpace(widget);
}
if (relativeSize.getHeight() >= 0) {
@@ -2120,7 +1968,7 @@ public class ApplicationConnection {
height -= renderSpace.getScrollbarSize();
}
if (validatingLayouts && height <= 0) {
- zeroHeightComponents.add(cd.getComponent());
+ zeroHeightComponents.add(paintable);
}
height = (int) (height * relativeSize.getHeight() / 100.0);
@@ -2130,14 +1978,20 @@ public class ApplicationConnection {
}
if (debugSizes) {
- VConsole.log("Widget " + Util.getSimpleName(widget) + "/"
- + getPid(widget.getElement()) + " relative height "
- + relativeSize.getHeight() + "% of "
- + renderSpace.getHeight() + "px (reported by "
-
- + Util.getSimpleName(parent) + "/"
- + (parent == null ? "?" : parent.hashCode())
- + ") : " + height + "px");
+ VConsole.log("Widget "
+ + Util.getSimpleName(widget)
+ + "/"
+ + paintableMap.getPid(paintable)
+ + " relative height "
+ + relativeSize.getHeight()
+ + "% of "
+ + renderSpace.getHeight()
+ + "px (reported by "
+
+ + Util.getSimpleName(parentPaintable)
+ + "/"
+ + (parentPaintable == null ? "?" : parentPaintable
+ .hashCode()) + ") : " + height + "px");
}
widget.setHeight(height + "px");
} else {
@@ -2169,7 +2023,7 @@ public class ApplicationConnection {
width -= renderSpace.getScrollbarSize();
}
if (validatingLayouts && width <= 0) {
- zeroWidthComponents.add(cd.getComponent());
+ zeroWidthComponents.add(paintable);
}
width = (int) (width * relativeSize.getWidth() / 100.0);
@@ -2179,13 +2033,20 @@ public class ApplicationConnection {
}
if (debugSizes) {
- VConsole.log("Widget " + Util.getSimpleName(widget) + "/"
- + getPid(widget.getElement()) + " relative width "
- + relativeSize.getWidth() + "% of "
- + renderSpace.getWidth() + "px (reported by "
- + Util.getSimpleName(parent) + "/"
- + (parent == null ? "?" : getPid(parent)) + ") : "
- + width + "px");
+ VConsole.log("Widget "
+ + Util.getSimpleName(widget)
+ + "/"
+ + paintableMap.getPid(paintable)
+ + " relative width "
+ + relativeSize.getWidth()
+ + "% of "
+ + renderSpace.getWidth()
+ + "px (reported by "
+ + Util.getSimpleName(parentPaintable)
+ + "/"
+ + (parentPaintable == null ? "?" : paintableMap
+ .getPid(parentPaintable)) + ") : " + width
+ + "px");
}
widget.setWidth(width + "px");
} else {
@@ -2205,9 +2066,8 @@ public class ApplicationConnection {
* @param child
* @return true if the child has a relative size
*/
- public boolean handleComponentRelativeSize(Widget child) {
- return handleComponentRelativeSize(idToPaintableDetail.get(getPid(child
- .getElement())));
+ public boolean handleComponentRelativeSize(Widget widget) {
+ return handleComponentRelativeSize(paintableMap.getPaintable(widget));
}
@@ -2219,8 +2079,7 @@ public class ApplicationConnection {
* @return the the size if the paintable is relatively sized, -1 otherwise
*/
public FloatSize getRelativeSize(Widget widget) {
- return idToPaintableDetail.get(getPid(widget.getElement()))
- .getRelativeSize();
+ return paintableMap.getRelativeSize(paintableMap.getPaintable(widget));
}
/**
@@ -2235,27 +2094,18 @@ public class ApplicationConnection {
* UIDL to create Paintable from.
* @return Either existing or new Paintable corresponding to UIDL.
*/
- public Paintable getPaintable(UIDL uidl) {
- final String id = uidl.getId();
- Paintable w = getPaintable(id);
- if (w != null) {
- return w;
- } else {
- w = widgetSet.createWidget(uidl, configuration);
- registerPaintable(id, w);
- return w;
-
+ public VPaintableWidget getPaintable(UIDL uidl) {
+ final String pid = uidl.getId();
+ if (!paintableMap.hasPaintable(pid)) {
+ // Create and register a new paintable if no old was found
+ VPaintableWidget p = widgetSet.createWidget(uidl, configuration);
+ if (p instanceof VAbstractPaintableWidget) {
+ ((VAbstractPaintableWidget) p).setConnection(this);
+ ((VAbstractPaintableWidget) p).init();
+ }
+ paintableMap.registerPaintable(pid, p);
}
- }
-
- /**
- * Returns a Paintable element by its root element
- *
- * @param element
- * Root element of the paintable
- */
- public Paintable getPaintable(Element element) {
- return getPaintable(getPid(element));
+ return (VPaintableWidget) paintableMap.getPaintable(pid);
}
/**
@@ -2348,16 +2198,12 @@ public class ApplicationConnection {
* Updating TooltipInfo is done in updateComponent method.
*
*/
- public TooltipInfo getTooltipTitleInfo(Paintable titleOwner, Object key) {
+ public TooltipInfo getTooltipTitleInfo(VPaintableWidget titleOwner,
+ Object key) {
if (null == titleOwner) {
return null;
}
- ComponentDetail cd = idToPaintableDetail.get(getPid(titleOwner));
- if (null != cd) {
- return cd.getTooltipInfo(key);
- } else {
- return null;
- }
+ return paintableMap.getTooltipInfo(titleOwner, key);
}
private final VTooltip tooltip = new VTooltip(this);
@@ -2372,7 +2218,7 @@ public class ApplicationConnection {
* @param event
* @param owner
*/
- public void handleTooltipEvent(Event event, Paintable owner) {
+ public void handleTooltipEvent(Event event, VPaintableWidget owner) {
tooltip.handleTooltipEvent(event, owner, null);
}
@@ -2390,24 +2236,12 @@ public class ApplicationConnection {
* the key for tooltip if this is "additional" tooltip, null for
* components "main tooltip"
*/
- public void handleTooltipEvent(Event event, Paintable owner, Object key) {
+ public void handleTooltipEvent(Event event, VPaintableWidget owner,
+ Object key) {
tooltip.handleTooltipEvent(event, owner, key);
}
- /**
- * Adds PNG-fix conditionally (only for IE6) to the specified IMG -element.
- *
- * @param el
- * the IMG element to fix
- */
- public void addPngFix(Element el) {
- BrowserInfo b = BrowserInfo.get();
- if (b.isIE6()) {
- Util.addPngFix(el);
- }
- }
-
/*
* Helper to run layout functions triggered by child components with a
* decent interval.
@@ -2427,11 +2261,13 @@ public class ApplicationConnection {
@Override
public void run() {
VConsole.log("Running re-layout of " + view.getClass().getName());
- runDescendentsLayout(view);
+ runDescendentsLayout(view.getWidgetForPaintable());
isPending = false;
}
};
+ private VPaintableMap paintableMap = GWT.create(VPaintableMap.class);
+
/**
* Components can call this function to run all layout functions. This is
* usually done, when component knows that its size has changed.
@@ -2440,24 +2276,6 @@ public class ApplicationConnection {
layoutTimer.schedule(500);
}
- private String windowName = null;
-
- /**
- * Reset the name of the current browser-window. This should reflect the
- * window-name used in the server, but might be different from the
- * window-object target-name on client.
- *
- * @param stringAttribute
- * New name for the window.
- */
- public void setWindowName(String newName) {
- windowName = newName;
- }
-
- protected String getWindowName() {
- return windowName;
- }
-
protected String getUidlSecurityKey() {
return uidlSecurityKey;
}
@@ -2469,8 +2287,8 @@ public class ApplicationConnection {
* @param component
* the Paintable whose caption has changed
*/
- public void captionSizeUpdated(Paintable component) {
- componentCaptionSizeChanges.add(component);
+ public void captionSizeUpdated(Widget widget) {
+ componentCaptionSizeChanges.add(widget);
}
/**
@@ -2478,7 +2296,7 @@ public class ApplicationConnection {
*
* @return the main view
*/
- public VView getView() {
+ public VViewPaintable getView() {
return view;
}
@@ -2488,7 +2306,7 @@ public class ApplicationConnection {
* this method.
* <p>
* Component must also pipe events to
- * {@link #handleTooltipEvent(Event, Paintable, Object)} method.
+ * {@link #handleTooltipEvent(Event, VPaintableWidget, Object)} method.
* <p>
* This method can also be used to deregister tooltips by using null as
* tooltip
@@ -2498,17 +2316,16 @@ public class ApplicationConnection {
* @param key
* key assosiated with given tooltip. Can be any object. For
* example a related dom element. Same key must be given for
- * {@link #handleTooltipEvent(Event, Paintable, Object)} method.
+ * {@link #handleTooltipEvent(Event, VPaintableWidget, Object)}
+ * method.
*
* @param tooltip
* the TooltipInfo object containing details shown in tooltip,
* null if deregistering tooltip
*/
- public void registerTooltip(Paintable paintable, Object key,
+ public void registerTooltip(VPaintableWidget paintable, Object key,
TooltipInfo tooltip) {
- ComponentDetail componentDetail = idToPaintableDetail
- .get(getPid(paintable));
- componentDetail.putAdditionalTooltip(key, tooltip);
+ paintableMap.registerTooltip(paintable, key, tooltip);
}
/**
@@ -2532,9 +2349,9 @@ public class ApplicationConnection {
* @return true if at least one listener has been registered on server side
* for the event identified by eventIdentifier.
*/
- public boolean hasEventListeners(Paintable paintable, String eventIdentifier) {
- return idToPaintableDetail.get(getPid(paintable)).hasEventListeners(
- eventIdentifier);
+ public boolean hasEventListeners(VPaintableWidget paintable,
+ String eventIdentifier) {
+ return paintableMap.hasEventListeners(paintable, eventIdentifier);
}
/**
@@ -2578,4 +2395,40 @@ public class ApplicationConnection {
return uri;
}
+ VPaintableMap getPaintableMap() {
+ return paintableMap;
+ }
+
+ @Deprecated
+ public void unregisterPaintable(VPaintable p) {
+ paintableMap.unregisterPaintable(p);
+ }
+
+ public VTooltip getVTooltip() {
+ return tooltip;
+ }
+
+ @Deprecated
+ public void handleWidgetTooltipEvent(Event event, Widget owner, Object key) {
+ handleTooltipEvent(event, getPaintableMap().getPaintable(owner), key);
+
+ }
+
+ @Deprecated
+ public void handleWidgetTooltipEvent(Event event, Widget owner) {
+ handleTooltipEvent(event, getPaintableMap().getPaintable(owner));
+
+ }
+
+ @Deprecated
+ public void registerWidgetTooltip(Widget owner, Object key, TooltipInfo info) {
+ registerTooltip(getPaintableMap().getPaintable(owner), key, info);
+ }
+
+ @Deprecated
+ public boolean hasWidgetEventListeners(Widget widget, String eventIdentifier) {
+ return hasEventListeners(getPaintableMap().getPaintable(widget),
+ eventIdentifier);
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
index fd80b917df..e5006f4a9c 100644
--- a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
+++ b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
@@ -4,8 +4,6 @@
package com.vaadin.terminal.gwt.client;
-import java.util.Date;
-
import com.google.gwt.user.client.ui.RootPanel;
/**
@@ -192,14 +190,6 @@ public class BrowserInfo {
return isSafari() && browserDetails.getBrowserMajorVersion() == 4;
}
- public boolean isIE6() {
- return isIE() && browserDetails.getBrowserMajorVersion() == 6;
- }
-
- public boolean isIE7() {
- return isIE() && browserDetails.getBrowserMajorVersion() == 7;
- }
-
public boolean isIE8() {
return isIE() && browserDetails.getBrowserMajorVersion() == 8;
}
@@ -220,23 +210,6 @@ public class BrowserInfo {
return browserDetails.isWebKit();
}
- public boolean isFF2() {
- // FIXME: Should use browserVersion
- return browserDetails.isFirefox()
- && browserDetails.getBrowserEngineVersion() == 1.8;
- }
-
- public boolean isFF3() {
- // FIXME: Should use browserVersion
- return browserDetails.isFirefox()
- && browserDetails.getBrowserEngineVersion() == 1.9;
- }
-
- public boolean isFF4() {
- return browserDetails.isFirefox()
- && browserDetails.getBrowserMajorVersion() == 4;
- }
-
/**
* Returns the Gecko version if the browser is Gecko based. The Gecko
* version for Firefox 2 is 1.8 and 1.9 for Firefox 3.
@@ -311,88 +284,6 @@ public class BrowserInfo {
}-*/;
/**
- * Get's the timezone offset from GMT in minutes, as reported by the
- * browser. DST affects this value.
- *
- * @return offset to GMT in minutes
- */
- public native int getTimezoneOffset()
- /*-{
- return new Date().getTimezoneOffset();
- }-*/;
-
- /**
- * Gets the timezone offset from GMT in minutes, as reported by the browser
- * AND adjusted to ignore daylight savings time. DST does not affect this
- * value.
- *
- * @return offset to GMT in minutes
- */
- public native int getRawTimezoneOffset()
- /*-{
- var d = new Date();
- var tzo1 = d.getTimezoneOffset(); // current offset
-
- for (var m=12;m>0;m--) {
- d.setUTCMonth(m);
- var tzo2 = d.getTimezoneOffset();
- if (tzo1 != tzo2) {
- // NOTE js indicates this 'backwards' (e.g -180)
- return (tzo1 > tzo2 ? tzo1 : tzo2); // offset w/o DST
- }
- }
-
- return tzo1; // no DST
-
- }-*/;
-
- /**
- * Gets the difference in minutes between the browser's GMT timezone and
- * DST.
- *
- * @return the amount of minutes that the timezone shifts when DST is in
- * effect
- */
- public native int getDSTSavings()
- /*-{
- var d = new Date();
- var tzo1 = d.getTimezoneOffset(); // current offset
-
- for (var m=12;m>0;m--) {
- d.setUTCMonth(m);
- var tzo2 = d.getTimezoneOffset();
- if (tzo1 != tzo2) {
- // NOTE js indicates this 'backwards' (e.g -180)
- return (tzo1 > tzo2 ? tzo1-tzo2 : tzo2-tzo1); // offset w/o DST
- }
- }
-
- return 0; // no DST
- }-*/;
-
- /**
- * Determines whether daylight savings time (DST) is currently in effect in
- * the region of the browser or not.
- *
- * @return true if the browser resides at a location that currently is in
- * DST
- */
- public boolean isDSTInEffect() {
- return getTimezoneOffset() != getRawTimezoneOffset();
- }
-
- /**
- * Returns the current date and time of the browser. This will not be
- * entirely accurate due to varying network latencies, but should provide a
- * close-enough value for most cases.
- *
- * @return the current date and time of the browser.
- */
- public Date getCurrentDate() {
- return new Date();
- }
-
- /**
* @return true if the browser runs on a touch based device.
*/
public boolean isTouchDevice() {
diff --git a/src/com/vaadin/terminal/gwt/client/ComponentDetail.java b/src/com/vaadin/terminal/gwt/client/ComponentDetail.java
index 7fc93b2a3e..8e4e13aa1c 100644
--- a/src/com/vaadin/terminal/gwt/client/ComponentDetail.java
+++ b/src/com/vaadin/terminal/gwt/client/ComponentDetail.java
@@ -11,14 +11,10 @@ import com.vaadin.terminal.gwt.client.RenderInformation.Size;
class ComponentDetail {
- private Paintable component;
private TooltipInfo tooltipInfo = new TooltipInfo();
- private String pid;
- public ComponentDetail(ApplicationConnection client, String pid,
- Paintable component) {
- this.component = component;
- this.pid = pid;
+ public ComponentDetail() {
+
}
/**
@@ -53,20 +49,6 @@ class ComponentDetail {
private HashMap<Object, TooltipInfo> additionalTooltips;
/**
- * @return the pid
- */
- String getPid() {
- return pid;
- }
-
- /**
- * @return the component
- */
- Paintable getComponent() {
- return component;
- }
-
- /**
* @return the relativeSize
*/
FloatSize getRelativeSize() {
diff --git a/src/com/vaadin/terminal/gwt/client/ComponentLocator.java b/src/com/vaadin/terminal/gwt/client/ComponentLocator.java
index b4489df81e..f49f99a477 100644
--- a/src/com/vaadin/terminal/gwt/client/ComponentLocator.java
+++ b/src/com/vaadin/terminal/gwt/client/ComponentLocator.java
@@ -78,7 +78,7 @@ public class ComponentLocator {
Element e = targetElement;
while (true) {
- pid = client.getPid(e);
+ pid = VPaintableMap.get(client).getPid(e);
if (pid != null) {
break;
}
@@ -94,7 +94,8 @@ public class ComponentLocator {
// If we found a Paintable then we use that as reference. We should
// find the Paintable for all but very special cases (like
// overlays).
- w = (Widget) client.getPaintable(pid);
+ w = ((VPaintableWidget) VPaintableMap.get(client).getPaintable(pid))
+ .getWidgetForPaintable();
/*
* Still if the Paintable contains a widget that implements
@@ -364,7 +365,7 @@ public class ComponentLocator {
return null;
}
- String pid = client.getPid(w.getElement());
+ String pid = VPaintableMap.get(client).getPid(w.getElement());
if (isStaticPid(pid)) {
return pid;
}
@@ -374,7 +375,7 @@ public class ComponentLocator {
} else if (w instanceof VWindow) {
VWindow win = (VWindow) w;
ArrayList<VWindow> subWindowList = client.getView()
- .getSubWindowList();
+ .getWidgetForPaintable().getSubWindowList();
int indexOfSubWindow = subWindowList.indexOf(win);
return PARENTCHILD_SEPARATOR + "VWindow[" + indexOfSubWindow + "]";
} else if (w instanceof RootPanel) {
@@ -434,10 +435,11 @@ public class ComponentLocator {
if (part.equals(ROOT_ID)) {
w = RootPanel.get();
} else if (part.equals("")) {
- w = client.getView();
+ w = client.getView().getWidgetForPaintable();
} else if (w == null) {
// Must be static pid (PID_S*)
- w = (Widget) client.getPaintable(part);
+ w = ((VPaintableWidget) VPaintableMap.get(client).getPaintable(
+ part)).getWidgetForPaintable();
} else if (part.startsWith("domChild[")) {
// The target widget has been found and the rest identifies the
// element
@@ -463,7 +465,8 @@ public class ComponentLocator {
* compatibility
*/
if (widgetClassName.equals("VWindow")) {
- iterator = client.getView().getSubWindowList().iterator();
+ iterator = client.getView().getWidgetForPaintable()
+ .getSubWindowList().iterator();
} else if (widgetClassName.equals("VContextMenu")) {
return client.getContextMenu();
} else {
diff --git a/src/com/vaadin/terminal/gwt/client/Console.java b/src/com/vaadin/terminal/gwt/client/Console.java
index 483ab8e0fd..cf5402a2af 100644
--- a/src/com/vaadin/terminal/gwt/client/Console.java
+++ b/src/com/vaadin/terminal/gwt/client/Console.java
@@ -22,8 +22,8 @@ public interface Console {
public abstract void printLayoutProblems(ValueMap meta,
ApplicationConnection applicationConnection,
- Set<Paintable> zeroHeightComponents,
- Set<Paintable> zeroWidthComponents);
+ Set<VPaintableWidget> zeroHeightComponents,
+ Set<VPaintableWidget> zeroWidthComponents);
public abstract void setQuietMode(boolean quietDebugMode);
diff --git a/src/com/vaadin/terminal/gwt/client/Container.java b/src/com/vaadin/terminal/gwt/client/Container.java
index 83f104886f..b573fd934e 100644
--- a/src/com/vaadin/terminal/gwt/client/Container.java
+++ b/src/com/vaadin/terminal/gwt/client/Container.java
@@ -8,7 +8,11 @@ import java.util.Set;
import com.google.gwt.user.client.ui.Widget;
-public interface Container extends Paintable {
+/**
+ * @deprecated To be removed before 7.0.0
+ */
+@Deprecated
+public interface Container {
/**
* Replace child of this layout with another component.
@@ -33,23 +37,6 @@ public interface Container extends Paintable {
boolean hasChildComponent(Widget component);
/**
- * Update child components caption, description and error message.
- *
- * <p>
- * Each component is responsible for maintaining its caption, description
- * and error message. In most cases components doesn't want to do that and
- * those elements reside outside of the component. Because of this layouts
- * must provide service for it's childen to show those elements for them.
- * </p>
- *
- * @param component
- * Child component for which service is requested.
- * @param uidl
- * UIDL of the child component.
- */
- void updateCaption(Paintable component, UIDL uidl);
-
- /**
* Called when a child components size has been updated in the rendering
* phase.
*
@@ -58,7 +45,7 @@ public interface Container extends Paintable {
* @return true if the size of the Container remains the same, false if the
* event need to be propagated to the Containers parent
*/
- boolean requestLayout(Set<Paintable> children);
+ boolean requestLayout(Set<Widget> children);
/**
* Returns the size currently allocated for the child component.
diff --git a/src/com/vaadin/terminal/gwt/client/EventHelper.java b/src/com/vaadin/terminal/gwt/client/EventHelper.java
index 600baf8c9d..10822f48c9 100644
--- a/src/com/vaadin/terminal/gwt/client/EventHelper.java
+++ b/src/com/vaadin/terminal/gwt/client/EventHelper.java
@@ -40,7 +40,7 @@ import com.google.gwt.event.shared.HandlerRegistration;
*/
public class EventHelper {
- public static HandlerRegistration updateFocusHandler(Paintable paintable,
+ public static HandlerRegistration updateFocusHandler(VPaintableWidget paintable,
ApplicationConnection client,
HandlerRegistration handlerRegistration) {
if (client.hasEventListeners(paintable, FOCUS)) {
@@ -57,7 +57,7 @@ public class EventHelper {
return null;
}
- public static HandlerRegistration updateBlurHandler(Paintable paintable,
+ public static HandlerRegistration updateBlurHandler(VPaintableWidget paintable,
ApplicationConnection client,
HandlerRegistration handlerRegistration) {
if (client.hasEventListeners(paintable, BLUR)) {
diff --git a/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java b/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java
deleted file mode 100644
index 217013095a..0000000000
--- a/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-/*
- * Copyright 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.terminal.gwt.client;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.impl.HistoryImpl;
-
-/**
- * A slightly modified version of GWT's HistoryImplIE6 to bypass bug #2931. Also
- * combined with HistoryImplFrame.
- *
- * This class should be removed if GWT issue 3890 gets resolved. (Also remember
- * to removed deferred binding rule from .gwt.xml file).
- */
-public class HistoryImplIEVaadin extends HistoryImpl {
-
- private static native Element findHistoryFrame()
- /*-{
- return $doc.getElementById('__gwt_historyFrame');
- }-*/;
-
- private static native Element getTokenElement(Element historyFrame)
- /*-{
- // Initialize the history iframe. If '__gwt_historyToken' already exists, then
- // we're probably backing into the app, so _don't_ set the iframe's location.
- if (historyFrame.contentWindow) {
- var doc = historyFrame.contentWindow.document;
- return doc.getElementById('__gwt_historyToken');
- }
- }-*/;
-
- protected Element historyFrame;
-
- @Override
- protected final void nativeUpdate(String historyToken) {
- /*
- * Must update the location hash since it isn't already correct.
- */
- updateHash(historyToken);
- navigateFrame(historyToken);
- }
-
- @Override
- protected final void nativeUpdateOnEvent(String historyToken) {
- updateHash(historyToken);
- }
-
- /**
- * Sanitizes an untrusted string to be used in an HTML context. NOTE: This
- * method of escaping strings should only be used on Internet Explorer.
- *
- * @param maybeHtml
- * untrusted string that may contain html
- * @return sanitized string
- */
- private static String escapeHtml(String maybeHtml) {
- final Element div = DOM.createDiv();
- DOM.setInnerText(div, maybeHtml);
- return DOM.getInnerHTML(div);
- }
-
- /**
- * For IE6, reading from $wnd.location.hash drops part of the fragment if
- * the fragment contains a '?'. To avoid this bug, we use location.href
- * instead.
- */
- private static native String getLocationHash()
- /*-{
- var href = $wnd.location.href;
- var hashLoc = href.lastIndexOf("#");
- return (hashLoc > 0) ? href.substring(hashLoc) : "";
- }-*/;
-
- @Override
- public boolean init() {
- historyFrame = findHistoryFrame();
- if (historyFrame == null) {
- return false;
- }
-
- initHistoryToken();
-
- // Initialize the history iframe. If a token element already exists,
- // then
- // we're probably backing into the app, so _don't_ create a new item.
- Element tokenElement = getTokenElement(historyFrame);
- if (tokenElement != null) {
- setToken(getTokenElementContent(tokenElement));
- } else {
- navigateFrame(getToken());
- }
-
- injectGlobalHandler();
-
- initUrlCheckTimer();
- return true;
- }
-
- protected native String getTokenElementContent(Element tokenElement)
- /*-{
- return tokenElement.innerText;
- }-*/;
-
- protected native void initHistoryToken()
- /*-{
- // Assume an empty token.
- var token = '';
- // Get the initial token from the url's hash component.
- var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()();
- if (hash.length > 0) {
- try {
- token = this.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1));
- } catch (e) {
- // Clear the bad hash (this can't have been a valid token).
- $wnd.location.hash = '';
- }
- }
- @com.google.gwt.user.client.impl.HistoryImpl::setToken(Ljava/lang/String;)(token);
- }-*/;
-
- protected native void injectGlobalHandler()
- /*-{
- var historyImplRef = this;
-
- $wnd.__gwt_onHistoryLoad = function(token) {
- historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::newItemOnEvent(Ljava/lang/String;)(token);
- };
- }-*/;
-
- protected native void navigateFrame(String token)
- /*-{
- var escaped = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::escapeHtml(Ljava/lang/String;)(token);
- var doc = this.@com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::historyFrame.contentWindow.document;
- doc.open();
- doc.write('<html><body onload="if(parent.__gwt_onHistoryLoad)parent.__gwt_onHistoryLoad(__gwt_historyToken.innerText)"><div id="__gwt_historyToken">' + escaped + '</div></body></html>');
- doc.close();
- }-*/;
-
- protected native void updateHash(String token)
- /*-{
- $wnd.location.hash = this.@com.google.gwt.user.client.impl.HistoryImpl::encodeFragment(Ljava/lang/String;)(token);
- }-*/;
-
- private native void initUrlCheckTimer()
- /*-{
- // This is the URL check timer. It detects when an unexpected change
- // occurs in the document's URL (e.g. when the user enters one manually
- // or selects a 'favorite', but only the #hash part changes). When this
- // occurs, we _must_ reload the page. This is because IE has a really
- // nasty bug that totally mangles its history stack and causes the location
- // bar in the UI to stop working under these circumstances.
- var historyImplRef = this;
- var urlChecker = function() {
- $wnd.setTimeout(urlChecker, 250);
- var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()();
- if (hash.length > 0) {
- var token = '';
- try {
- token = historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1));
- } catch (e) {
- // If there's a bad hash, always reload. This could only happen if
- // if someone entered or linked to a bad url.
- $wnd.location.reload();
- }
-
- var historyToken = @com.google.gwt.user.client.impl.HistoryImpl::getToken()();
- if (token != historyToken) {
- $wnd.location.reload();
- }
- }
- };
- urlChecker();
- }-*/;
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/NullConsole.java b/src/com/vaadin/terminal/gwt/client/NullConsole.java
index 12df4b323b..31aa4f74d3 100644
--- a/src/com/vaadin/terminal/gwt/client/NullConsole.java
+++ b/src/com/vaadin/terminal/gwt/client/NullConsole.java
@@ -32,8 +32,8 @@ public class NullConsole implements Console {
public void printLayoutProblems(ValueMap meta,
ApplicationConnection applicationConnection,
- Set<Paintable> zeroHeightComponents,
- Set<Paintable> zeroWidthComponents) {
+ Set<VPaintableWidget> zeroHeightComponents,
+ Set<VPaintableWidget> zeroWidthComponents) {
}
public void log(Throwable e) {
diff --git a/src/com/vaadin/terminal/gwt/client/Paintable.java b/src/com/vaadin/terminal/gwt/client/Paintable.java
deleted file mode 100644
index 62abeab5a0..0000000000
--- a/src/com/vaadin/terminal/gwt/client/Paintable.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-/**
- * An interface used by client-side widgets or paintable parts to receive
- * updates from the corresponding server-side components in the form of
- * {@link UIDL}.
- *
- * Updates can be sent back to the server using the
- * {@link ApplicationConnection#updateVariable()} methods.
- */
-public interface Paintable {
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client);
-}
diff --git a/src/com/vaadin/terminal/gwt/client/UIDL.java b/src/com/vaadin/terminal/gwt/client/UIDL.java
index a6298af8d1..b828e644dd 100644
--- a/src/com/vaadin/terminal/gwt/client/UIDL.java
+++ b/src/com/vaadin/terminal/gwt/client/UIDL.java
@@ -16,7 +16,7 @@ import com.vaadin.ui.Component;
/**
* When a component is updated, it's client side widget's
- * {@link Paintable#updateFromUIDL(UIDL, ApplicationConnection)
+ * {@link VPaintableWidget#updateFromUIDL(UIDL, ApplicationConnection)
* updateFromUIDL()} will be called with the updated ("changes") UIDL received
* from the server.
* <p>
@@ -55,7 +55,7 @@ public final class UIDL extends JavaScriptObject {
* AbstractComponent.paintContent()}. Note that if the UIDL corresponds to a
* Paintable, a component identifier will be returned instead - this is used
* internally and is not needed within
- * {@link Paintable#updateFromUIDL(UIDL, ApplicationConnection)
+ * {@link VPaintableWidget#updateFromUIDL(UIDL, ApplicationConnection)
* updateFromUIDL()}.
*
* @return the name for this section
@@ -516,9 +516,10 @@ public final class UIDL extends JavaScriptObject {
* the name of the attribute
* @return the Paintable referenced by the attribute, if it exists
*/
- public Paintable getPaintableAttribute(String name,
+ public VPaintable getPaintableAttribute(String name,
ApplicationConnection connection) {
- return connection.getPaintable(getStringAttribute(name));
+ return VPaintableMap.get(connection).getPaintable(
+ getStringAttribute(name));
}
/**
@@ -528,9 +529,10 @@ public final class UIDL extends JavaScriptObject {
* the name of the variable
* @return the Paintable referenced by the variable, if it exists
*/
- public Paintable getPaintableVariable(String name,
+ public VPaintable getPaintableVariable(String name,
ApplicationConnection connection) {
- return connection.getPaintable(getStringVariable(name));
+ return VPaintableMap.get(connection).getPaintable(
+ getStringVariable(name));
}
/**
diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java
index 3dbbd22329..4514adf7e0 100644
--- a/src/com/vaadin/terminal/gwt/client/Util.java
+++ b/src/com/vaadin/terminal/gwt/client/Util.java
@@ -11,10 +11,8 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
-import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
@@ -68,7 +66,7 @@ public class Util {
}-*/;
private static final int LAZY_SIZE_CHANGE_TIMEOUT = 400;
- private static Set<Paintable> latelyChangedWidgets = new HashSet<Paintable>();
+ private static Set<Widget> latelyChangedWidgets = new HashSet<Widget>();
private static Timer lazySizeChangeTimer = new Timer() {
private boolean lazySizeChangeTimerScheduled = false;
@@ -107,12 +105,12 @@ public class Util {
* @param lazy
* run componentSizeUpdated lazyly
*/
- public static void notifyParentOfSizeChange(Paintable widget, boolean lazy) {
+ public static void notifyParentOfSizeChange(Widget widget, boolean lazy) {
if (lazy) {
latelyChangedWidgets.add(widget);
lazySizeChangeTimer.schedule(LAZY_SIZE_CHANGE_TIMEOUT);
} else {
- Set<Paintable> widgets = new HashSet<Paintable>();
+ Set<Widget> widgets = new HashSet<Widget>();
widgets.add(widget);
Util.componentSizeUpdated(widgets);
}
@@ -124,15 +122,14 @@ public class Util {
*
* @param paintables
*/
- public static void componentSizeUpdated(Set<Paintable> paintables) {
- if (paintables.isEmpty()) {
+ public static void componentSizeUpdated(Set<Widget> widgets) {
+ if (widgets.isEmpty()) {
return;
}
- Map<Container, Set<Paintable>> childWidgets = new HashMap<Container, Set<Paintable>>();
+ Map<Container, Set<Widget>> childWidgets = new HashMap<Container, Set<Widget>>();
- for (Paintable paintable : paintables) {
- Widget widget = (Widget) paintable;
+ for (Widget widget : widgets) {
if (!widget.isAttached()) {
continue;
}
@@ -144,19 +141,19 @@ public class Util {
parent = parent.getParent();
}
if (parent != null) {
- Set<Paintable> set = childWidgets.get(parent);
+ Set<Widget> set = childWidgets.get(parent);
if (set == null) {
- set = new HashSet<Paintable>();
+ set = new HashSet<Widget>();
childWidgets.put((Container) parent, set);
}
- set.add(paintable);
+ set.add(widget);
}
}
- Set<Paintable> parentChanges = new HashSet<Paintable>();
+ Set<Widget> parentChanges = new HashSet<Widget>();
for (Container parent : childWidgets.keySet()) {
if (!parent.requestLayout(childWidgets.get(parent))) {
- parentChanges.add(parent);
+ parentChanges.add((Widget) parent);
}
}
@@ -196,48 +193,6 @@ public class Util {
return null;
}
- /**
- * Detects if current browser is IE.
- *
- * @deprecated use BrowserInfo class instead
- *
- * @return true if IE
- */
- @Deprecated
- public static boolean isIE() {
- return BrowserInfo.get().isIE();
- }
-
- /**
- * Detects if current browser is IE6.
- *
- * @deprecated use BrowserInfo class instead
- *
- * @return true if IE6
- */
- @Deprecated
- public static boolean isIE6() {
- return BrowserInfo.get().isIE6();
- }
-
- /**
- * @deprecated use BrowserInfo class instead
- * @return
- */
- @Deprecated
- public static boolean isIE7() {
- return BrowserInfo.get().isIE7();
- }
-
- /**
- * @deprecated use BrowserInfo class instead
- * @return
- */
- @Deprecated
- public static boolean isFF2() {
- return BrowserInfo.get().isFF2();
- }
-
private static final Element escapeHtmlHelper = DOM.createDiv();
/**
@@ -249,8 +204,8 @@ public class Util {
public static String escapeHTML(String html) {
DOM.setInnerText(escapeHtmlHelper, html);
String escapedText = DOM.getInnerHTML(escapeHtmlHelper);
- if (BrowserInfo.get().isIE() && BrowserInfo.get().getIEVersion() < 9) {
- // #7478 IE6-IE8 "incorrectly" returns "<br>" for newlines set using
+ if (BrowserInfo.get().isIE8()) {
+ // #7478 IE8 "incorrectly" returns "<br>" for newlines set using
// setInnerText. The same for " " which is converted to "&nbsp;"
escapedText = escapedText.replaceAll("<(BR|br)>", "\n");
escapedText = escapedText.replaceAll("&nbsp;", " ");
@@ -275,48 +230,6 @@ public class Util {
}
/**
- * Adds transparent PNG fix to image element; only use for IE6.
- *
- * @param el
- * IMG element
- */
- public native static void addPngFix(Element el)
- /*-{
- el.attachEvent("onload", function() {
- @com.vaadin.terminal.gwt.client.Util::doIE6PngFix(Lcom/google/gwt/user/client/Element;)(el);
- },false);
- }-*/;
-
- private native static void doPngFix(Element el, String blankImageUrl)
- /*-{
- var src = el.src;
- if (src.indexOf(".png") < 1) return;
- var w = el.width || 16;
- var h = el.height || 16;
- if(h==30 || w==28) {
- setTimeout(function(){
- el.style.height = el.height + "px";
- el.style.width = el.width + "px";
- el.src = blankImageUrl;
- },10);
- } else {
- el.src = blankImageUrl;
- el.style.height = h + "px";
- el.style.width = w + "px";
- }
- el.style.padding = "0";
- el.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+src+"', sizingMethod='crop')";
- }-*/;
-
- public static void doIE6PngFix(Element el) {
- String blankImageUrl = GWT.getModuleBaseURL() + "ie6pngfix/blank.gif";
- String src = el.getAttribute("src");
- if (src != null && !src.equals(blankImageUrl)) {
- doPngFix(el, blankImageUrl);
- }
- }
-
- /**
* Clones given element as in JavaScript.
*
* Deprecate this if there appears similar method into GWT someday.
@@ -334,11 +247,7 @@ public class Util {
public static int measureHorizontalPaddingAndBorder(Element element,
int paddingGuess) {
String originalWidth = DOM.getStyleAttribute(element, "width");
- String originalOverflow = "";
- if (BrowserInfo.get().isIE6()) {
- originalOverflow = DOM.getStyleAttribute(element, "overflow");
- DOM.setStyleAttribute(element, "overflow", "hidden");
- }
+
int originalOffsetWidth = element.getOffsetWidth();
int widthGuess = (originalOffsetWidth - paddingGuess);
if (widthGuess < 1) {
@@ -348,9 +257,7 @@ public class Util {
int padding = element.getOffsetWidth() - widthGuess;
DOM.setStyleAttribute(element, "width", originalWidth);
- if (BrowserInfo.get().isIE6()) {
- DOM.setStyleAttribute(element, "overflow", originalOverflow);
- }
+
return padding;
}
@@ -378,23 +285,19 @@ public class Util {
int offsetWidth = element.getOffsetWidth();
int offsetHeight = element.getOffsetHeight();
- if (!BrowserInfo.get().isIE7()) {
- if (offsetHeight < 1) {
- offsetHeight = 1;
- }
- if (offsetWidth < 1) {
- offsetWidth = 10;
- }
- element.getStyle().setPropertyPx("height", offsetHeight);
+ if (offsetHeight < 1) {
+ offsetHeight = 1;
}
+ if (offsetWidth < 1) {
+ offsetWidth = 10;
+ }
+ element.getStyle().setPropertyPx("height", offsetHeight);
element.getStyle().setPropertyPx("width", offsetWidth);
borders = element.getOffsetWidth() - element.getClientWidth();
element.getStyle().setProperty("width", width);
- if (!BrowserInfo.get().isIE7()) {
- element.getStyle().setProperty("height", height);
- }
+ element.getStyle().setProperty("height", height);
} else {
borders = element.getOffsetWidth()
- element.getPropertyInt("clientWidth");
@@ -412,7 +315,6 @@ public class Util {
int offsetWidth = element.getOffsetWidth();
int offsetHeight = element.getOffsetHeight();
- // if (BrowserInfo.get().isIE6()) {
if (offsetHeight < 1) {
offsetHeight = 1;
}
@@ -420,7 +322,6 @@ public class Util {
offsetWidth = 10;
}
element.getStyle().setPropertyPx("width", offsetWidth);
- // }
element.getStyle().setPropertyPx("height", offsetHeight);
@@ -428,9 +329,7 @@ public class Util {
- element.getPropertyInt("clientHeight");
element.getStyle().setProperty("height", height);
- // if (BrowserInfo.get().isIE6()) {
element.getStyle().setProperty("width", width);
- // }
} else {
borders = element.getOffsetHeight()
- element.getPropertyInt("clientHeight");
@@ -714,13 +613,7 @@ public class Util {
}
public static void updateRelativeChildrenAndSendSizeUpdateEvent(
- ApplicationConnection client, HasWidgets container) {
- updateRelativeChildrenAndSendSizeUpdateEvent(client, container,
- (Paintable) container);
- }
-
- public static void updateRelativeChildrenAndSendSizeUpdateEvent(
- ApplicationConnection client, HasWidgets container, Paintable widget) {
+ ApplicationConnection client, HasWidgets container, Widget widget) {
/*
* Relative sized children must be updated first so the component has
* the correct outer dimensions when signaling a size change to the
@@ -732,7 +625,7 @@ public class Util {
client.handleComponentRelativeSize(w);
}
- HashSet<Paintable> widgets = new HashSet<Paintable>();
+ HashSet<Widget> widgets = new HashSet<Widget>();
widgets.add(widget);
Util.componentSizeUpdated(widgets);
}
@@ -823,33 +716,6 @@ public class Util {
}-*/;
/**
- * IE7 sometimes "forgets" to render content. This function runs a hack to
- * workaround the bug if needed. This happens easily in framset. See #3295.
- */
- public static void runIE7ZeroSizedBodyFix() {
- if (BrowserInfo.get().isIE7()) {
- int offsetWidth = RootPanel.getBodyElement().getOffsetWidth();
- if (offsetWidth == 0) {
- shakeBodyElement();
- }
- }
- }
-
- /**
- * Does some very small adjustments to body element. We need this just to
- * overcome some IE bugs.
- */
- public static void shakeBodyElement() {
- final DivElement shaker = Document.get().createDivElement();
- RootPanel.getBodyElement().insertBefore(shaker,
- RootPanel.getBodyElement().getFirstChildElement());
- shaker.getStyle().setPropertyPx("height", 0);
- shaker.setInnerHTML("&nbsp;");
- RootPanel.getBodyElement().removeChild(shaker);
-
- }
-
- /**
* Locates the child component of <literal>parent</literal> which contains
* the element <literal>element</literal>. The child component is also
* returned if "element" is part of its caption. If
@@ -867,30 +733,27 @@ public class Util {
* The widget that contains <literal>element</literal>.
* @param element
* An element that is a sub element of the parent
- * @return The Paintable which the element is a part of. Null if the element
- * does not belong to a child.
+ * @return The VPaintableWidget which the element is a part of. Null if the
+ * element does not belong to a child.
*/
- public static Paintable getChildPaintableForElement(
+ public static VPaintableWidget getChildPaintableForElement(
ApplicationConnection client, Container parent, Element element) {
Element rootElement = ((Widget) parent).getElement();
while (element != null && element != rootElement) {
- Paintable paintable = client.getPaintable(element);
+ VPaintableWidget paintable = VPaintableMap.get(client)
+ .getPaintable(element);
if (paintable == null) {
String ownerPid = VCaption.getCaptionOwnerPid(element);
if (ownerPid != null) {
- paintable = client.getPaintable(ownerPid);
+ paintable = (VPaintableWidget) VPaintableMap.get(client)
+ .getPaintable(ownerPid);
}
}
- if (paintable != null) {
- try {
- if (parent.hasChildComponent((Widget) paintable)) {
- return paintable;
- }
- } catch (ClassCastException e) {
- // We assume everything is a widget however there is no need
- // to crash everything if there is a paintable that is not.
- }
+ if (paintable != null
+ && parent.hasChildComponent(paintable
+ .getWidgetForPaintable())) {
+ return paintable;
}
element = (Element) element.getParentElement();
@@ -906,7 +769,7 @@ public class Util {
* <literal>element</literal> is not part of any child component, null is
* returned.
*
- * This method returns the deepest nested Paintable. See
+ * This method returns the deepest nested VPaintableWidget. See
* {@link #getChildPaintableForElement(ApplicationConnection, Container, Element)}
* for the immediate child component of parent that contains the element.
*
@@ -916,18 +779,20 @@ public class Util {
* The widget that contains <literal>element</literal>.
* @param element
* An element that is a sub element of the parent
- * @return The Paintable which the element is a part of. Null if the element
- * does not belong to a child.
+ * @return The VPaintableWidget which the element is a part of. Null if the
+ * element does not belong to a child.
*/
- public static Paintable getPaintableForElement(
+ public static VPaintableWidget getPaintableForElement(
ApplicationConnection client, Widget parent, Element element) {
Element rootElement = parent.getElement();
while (element != null && element != rootElement) {
- Paintable paintable = client.getPaintable(element);
+ VPaintableWidget paintable = VPaintableMap.get(client)
+ .getPaintable(element);
if (paintable == null) {
String ownerPid = VCaption.getCaptionOwnerPid(element);
if (ownerPid != null) {
- paintable = client.getPaintable(ownerPid);
+ paintable = (VPaintableWidget) VPaintableMap.get(client)
+ .getPaintable(ownerPid);
}
}
@@ -965,6 +830,24 @@ public class Util {
}-*/;
/**
+ * Helper method to find the nearest parent paintable instance by traversing
+ * the DOM upwards from given element.
+ *
+ * @param element
+ * the element to start from
+ */
+ public static VPaintableWidget findPaintable(ApplicationConnection client,
+ Element element) {
+ Widget widget = Util.findWidget(element, null);
+ VPaintableMap vPaintableMap = VPaintableMap.get(client);
+ while (widget != null && !vPaintableMap.isPaintable(widget)) {
+ widget = widget.getParent();
+ }
+ return vPaintableMap.getPaintable(widget);
+
+ }
+
+ /**
* Helper method to find first instance of given Widget type found by
* traversing DOM upwards from given element.
*
@@ -1073,7 +956,8 @@ public class Util {
private static void printPaintablesVariables(ArrayList<String[]> vars,
String id, ApplicationConnection c) {
- Paintable paintable = c.getPaintable(id);
+ VPaintableWidget paintable = (VPaintableWidget) VPaintableMap.get(c)
+ .getPaintable(id);
if (paintable != null) {
VConsole.log("\t" + id + " (" + paintable.getClass() + ") :");
for (String[] var : vars) {
diff --git a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java
index aaef981bab..89e106f063 100644
--- a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java
+++ b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java
@@ -22,6 +22,9 @@ public class VBrowserDetails implements Serializable {
private boolean isWebKit = false;
private boolean isPresto = false;
+ private boolean isChromeFrameCapable = false;
+ private boolean isChromeFrame = false;
+
private boolean isSafari = false;
private boolean isChrome = false;
private boolean isFirefox = false;
@@ -59,6 +62,10 @@ public class VBrowserDetails implements Serializable {
&& (userAgent.indexOf("webtv") == -1);
isFirefox = userAgent.indexOf(" firefox/") != -1;
+ // chromeframe
+ isChromeFrameCapable = userAgent.indexOf("chromeframe") != -1;
+ isChromeFrame = isChromeFrameCapable && !isChrome;
+
// Rendering engine version
try {
if (isGecko) {
@@ -210,6 +217,24 @@ public class VBrowserDetails implements Serializable {
}
/**
+ * Tests if the browser is capable of running ChromeFrame.
+ *
+ * @return true if it has ChromeFrame, false otherwise
+ */
+ public boolean isChromeFrameCapable() {
+ return isChromeFrameCapable;
+ }
+
+ /**
+ * Tests if the browser is running ChromeFrame.
+ *
+ * @return true if it is ChromeFrame, false otherwise
+ */
+ public boolean isChromeFrame() {
+ return isChromeFrame;
+ }
+
+ /**
* Tests if the browser is Opera.
*
* @return true if it is Opera, false otherwise
@@ -302,4 +327,30 @@ public class VBrowserDetails implements Serializable {
return isLinux;
}
+ /**
+ * Checks if the browser is so old that it simply won't work with a Vaadin
+ * application. NOTE that the browser might still be capable of running
+ * Crome Frame, so you might still want to check
+ * {@link #isChromeFrameCapable()} if this returns true.
+ *
+ * @return true if the browser won't work, false if not the browser is
+ * supported or might work
+ */
+ public boolean isTooOldToFunctionProperly() {
+ if (isIE() && getBrowserMajorVersion() < 8) {
+ return true;
+ }
+ if (isSafari() && getBrowserMajorVersion() < 5) {
+ return true;
+ }
+ if (isFirefox() && getBrowserMajorVersion() < 4) {
+ return true;
+ }
+ if (isOpera() && getBrowserMajorVersion() < 11) {
+ return true;
+ }
+
+ return false;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/VCaption.java b/src/com/vaadin/terminal/gwt/client/VCaption.java
index c4b61d2544..f6d8ffe58e 100644
--- a/src/com/vaadin/terminal/gwt/client/VCaption.java
+++ b/src/com/vaadin/terminal/gwt/client/VCaption.java
@@ -14,7 +14,7 @@ public class VCaption extends HTML {
public static final String CLASSNAME = "v-caption";
- private final Paintable owner;
+ private final VPaintableWidget owner;
private Element errorIndicatorElement;
@@ -29,7 +29,6 @@ public class VCaption extends HTML {
private final ApplicationConnection client;
private boolean placedAfterComponent = false;
- private boolean iconOnloadHandled = false;
private int maxWidth = -1;
@@ -49,13 +48,13 @@ public class VCaption extends HTML {
* null
* @param client
*/
- public VCaption(Paintable component, ApplicationConnection client) {
+ public VCaption(VPaintableWidget component, ApplicationConnection client) {
super();
this.client = client;
owner = component;
if (client != null && owner != null) {
- setOwnerPid(getElement(), client.getPid(owner));
+ setOwnerPid(getElement(), VPaintableMap.get(client).getPid(owner));
}
setStyleName(CLASSNAME);
@@ -112,7 +111,6 @@ public class VCaption extends HTML {
// Icon forces the caption to be above the component
placedAfterComponent = false;
- iconOnloadHandled = false;
icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON));
} else if (icon != null) {
@@ -246,16 +244,10 @@ public class VCaption extends HTML {
}
if (DOM.eventGetType(event) == Event.ONLOAD
- && icon.getElement() == target && !iconOnloadHandled) {
+ && icon.getElement() == target) {
icon.setWidth("");
icon.setHeight("");
- /*
- * IE6 pngFix causes two onload events to be fired and we want to
- * react only to the first one
- */
- iconOnloadHandled = true;
-
// if max width defined, recalculate
if (maxWidth != -1) {
setMaxWidth(maxWidth);
@@ -272,7 +264,8 @@ public class VCaption extends HTML {
* the responsibility of reacting to ONLOAD from VCaption to layouts
*/
if (owner != null) {
- Util.notifyParentOfSizeChange(owner, true);
+ Util.notifyParentOfSizeChange(owner.getWidgetForPaintable(),
+ true);
} else {
VConsole.log("Warning: Icon load event was not propagated because VCaption owner is unknown.");
}
@@ -301,7 +294,7 @@ public class VCaption extends HTML {
*
* @return owner Widget
*/
- public Paintable getOwner() {
+ public VPaintableWidget getOwner() {
return owner;
}
diff --git a/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java b/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java
index dbecf96dd0..bc1a240aa9 100644
--- a/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java
+++ b/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java
@@ -5,19 +5,19 @@
package com.vaadin.terminal.gwt.client;
import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.Widget;
public class VCaptionWrapper extends FlowPanel {
public static final String CLASSNAME = "v-captionwrapper";
VCaption caption;
- Paintable widget;
+ VPaintableWidget paintable;
- public VCaptionWrapper(Paintable toBeWrapped, ApplicationConnection client) {
+ public VCaptionWrapper(VPaintableWidget toBeWrapped,
+ ApplicationConnection client) {
caption = new VCaption(toBeWrapped, client);
add(caption);
- widget = toBeWrapped;
- add((Widget) widget);
+ paintable = toBeWrapped;
+ add(paintable.getWidgetForPaintable());
setStyleName(CLASSNAME);
}
@@ -26,7 +26,7 @@ public class VCaptionWrapper extends FlowPanel {
setVisible(!uidl.getBooleanAttribute("invisible"));
}
- public Paintable getPaintable() {
- return widget;
+ public VPaintableWidget getPaintable() {
+ return paintable;
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/VConsole.java b/src/com/vaadin/terminal/gwt/client/VConsole.java
index a01fa16558..137b6eb2a6 100644
--- a/src/com/vaadin/terminal/gwt/client/VConsole.java
+++ b/src/com/vaadin/terminal/gwt/client/VConsole.java
@@ -82,8 +82,8 @@ public class VConsole {
public static void printLayoutProblems(ValueMap meta,
ApplicationConnection applicationConnection,
- Set<Paintable> zeroHeightComponents,
- Set<Paintable> zeroWidthComponents) {
+ Set<VPaintableWidget> zeroHeightComponents,
+ Set<VPaintableWidget> zeroWidthComponents) {
impl.printLayoutProblems(meta, applicationConnection,
zeroHeightComponents, zeroWidthComponents);
}
diff --git a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
index c43581b000..76c312676a 100644
--- a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
+++ b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
@@ -90,14 +90,14 @@ public class VDebugConsole extends VOverlay implements Console {
for (ApplicationConnection a : ApplicationConfiguration
.getRunningApplications()) {
- Paintable paintable = Util.getPaintableForElement(a,
- a.getView(), eventTarget);
+ VPaintableWidget paintable = Util.getPaintableForElement(a,
+ a.getView().getWidgetForPaintable(), eventTarget);
if (paintable == null) {
paintable = Util.getPaintableForElement(a,
RootPanel.get(), eventTarget);
}
if (paintable != null) {
- String pid = a.getPid(paintable);
+ String pid = VPaintableMap.get(a).getPid(paintable);
VUIDLBrowser.highlight(paintable);
label.setText("Currently focused :"
+ paintable.getClass() + " ID:" + pid);
@@ -119,8 +119,8 @@ public class VDebugConsole extends VOverlay implements Console {
.getClientY());
for (ApplicationConnection a : ApplicationConfiguration
.getRunningApplications()) {
- Paintable paintable = Util.getPaintableForElement(a,
- a.getView(), eventTarget);
+ VPaintableWidget paintable = Util.getPaintableForElement(a,
+ a.getView().getWidgetForPaintable(), eventTarget);
if (paintable == null) {
paintable = Util.getPaintableForElement(a,
RootPanel.get(), eventTarget);
@@ -483,8 +483,8 @@ public class VDebugConsole extends VOverlay implements Console {
}-*/;
public void printLayoutProblems(ValueMap meta, ApplicationConnection ac,
- Set<Paintable> zeroHeightComponents,
- Set<Paintable> zeroWidthComponents) {
+ Set<VPaintableWidget> zeroHeightComponents,
+ Set<VPaintableWidget> zeroWidthComponents) {
JsArray<ValueMap> valueMapArray = meta
.getJSValueMapArray("invalidLayouts");
int size = valueMapArray.length();
@@ -521,9 +521,10 @@ public class VDebugConsole extends VOverlay implements Console {
}
private void printClientSideDetectedIssues(
- Set<Paintable> zeroHeightComponents, ApplicationConnection ac) {
- for (final Paintable paintable : zeroHeightComponents) {
- final Container layout = Util.getLayout((Widget) paintable);
+ Set<VPaintableWidget> zeroHeightComponents, ApplicationConnection ac) {
+ for (final VPaintableWidget paintable : zeroHeightComponents) {
+ final Container layout = Util.getLayout(paintable
+ .getWidgetForPaintable());
VerticalPanel errorDetails = new VerticalPanel();
errorDetails.add(new Label("" + Util.getSimpleName(paintable)
@@ -547,7 +548,8 @@ public class VDebugConsole extends VOverlay implements Console {
private void printLayoutError(ValueMap valueMap, SimpleTree root,
final ApplicationConnection ac) {
final String pid = valueMap.getString("id");
- final Paintable paintable = ac.getPaintable(pid);
+ final VPaintableWidget paintable = (VPaintableWidget) VPaintableMap
+ .get(ac).getPaintable(pid);
SimpleTree errorNode = new SimpleTree();
VerticalPanel errorDetails = new VerticalPanel();
@@ -565,7 +567,8 @@ public class VDebugConsole extends VOverlay implements Console {
emphasisInUi.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
if (paintable != null) {
- Element element2 = ((Widget) paintable).getElement();
+ Element element2 = paintable.getWidgetForPaintable()
+ .getElement();
Widget.setStyleName(element2, "invalidlayout",
emphasisInUi.getValue());
}
diff --git a/src/com/vaadin/terminal/gwt/client/VPaintable.java b/src/com/vaadin/terminal/gwt/client/VPaintable.java
new file mode 100644
index 0000000000..f7b7eaba83
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/VPaintable.java
@@ -0,0 +1,74 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client;
+
+/**
+ * Interface implemented by all client side classes that can be communicate with
+ * the server. Classes implementing this interface are initialized by the
+ * framework when needed and have the ability to communicate with the server.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
+public interface VPaintable {
+ /**
+ * TODO
+ *
+ * @param uidl
+ * @param client
+ */
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client);
+
+ // /**
+ // * Returns the id for this VPaintable. This must always be what has been
+ // set
+ // * using {@link #setId(String)}.
+ // *
+ // * @return The id for the VPaintable.
+ // */
+ // public String getId();
+ //
+ // /**
+ // * Sets the id for the VPaintable. This method is called once by the
+ // * framework when the VPaintable is initialized and should never be called
+ // * otherwise.
+ // * <p>
+ // * The VPaintable id is used to map the server and the client paintables
+ // * together. It is unique in this root and assigned by the framework.
+ // * </p>
+ // *
+ // * @param id
+ // * The id of the paintable.
+ // */
+ // public void setId(String id);
+
+ /**
+ * Gets ApplicationConnection instance that created this VPaintable.
+ *
+ * @return The ApplicationConnection as set by
+ * {@link #setConnection(ApplicationConnection)}
+ */
+ // public ApplicationConnection getConnection();
+
+ /**
+ * Sets the reference to ApplicationConnection. This method is called by the
+ * framework when the VPaintable is created and should never be called
+ * otherwise.
+ *
+ * @param connection
+ * The ApplicationConnection that created this VPaintable
+ */
+ // public void setConnection(ApplicationConnection connection);
+
+ /**
+ * Tests whether the component is enabled or not. A user can not interact
+ * with disabled components. Disabled components are rendered in a style
+ * that indicates the status, usually in gray color. Children of a disabled
+ * component are also disabled.
+ *
+ * @return true if the component is enabled, false otherwise
+ */
+ // public boolean isEnabled();
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VPaintableMap.java b/src/com/vaadin/terminal/gwt/client/VPaintableMap.java
new file mode 100644
index 0000000000..aa3e8e3cb8
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/VPaintableMap.java
@@ -0,0 +1,403 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.Paintable;
+import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
+import com.vaadin.terminal.gwt.client.RenderInformation.Size;
+
+public class VPaintableMap {
+
+ private Map<String, VPaintable> idToPaintable = new HashMap<String, VPaintable>();
+ private Map<VPaintable, String> paintableToId = new HashMap<VPaintable, String>();
+
+ public static VPaintableMap get(ApplicationConnection applicationConnection) {
+ return applicationConnection.getPaintableMap();
+ }
+
+ @Deprecated
+ private final ComponentDetailMap idToComponentDetail = ComponentDetailMap
+ .create();
+
+ private Set<String> unregistryBag = new HashSet<String>();
+
+ /**
+ * Returns a Paintable by its paintable id
+ *
+ * @param id
+ * The Paintable id
+ */
+ public VPaintable getPaintable(String pid) {
+ return idToPaintable.get(pid);
+ }
+
+ /**
+ * Returns a Paintable element by its root element
+ *
+ * @param element
+ * Root element of the paintable
+ */
+ public VPaintableWidget getPaintable(Element element) {
+ return (VPaintableWidget) getPaintable(getPid(element));
+ }
+
+ /**
+ * FIXME: What does this even do and why?
+ *
+ * @param pid
+ * @return
+ */
+ public boolean isDragAndDropPaintable(String pid) {
+ return (pid.startsWith("DD"));
+ }
+
+ /**
+ * Checks if a paintable with the given paintable id has been registered.
+ *
+ * @param pid
+ * The paintable id to check for
+ * @return true if a paintable has been registered with the given paintable
+ * id, false otherwise
+ */
+ public boolean hasPaintable(String pid) {
+ return idToPaintable.containsKey(pid);
+ }
+
+ /**
+ * Removes all registered paintable ids
+ */
+ public void clear() {
+ idToPaintable.clear();
+ paintableToId.clear();
+ idToComponentDetail.clear();
+ }
+
+ @Deprecated
+ public Widget getWidget(VPaintableWidget paintable) {
+ return paintable.getWidgetForPaintable();
+ }
+
+ @Deprecated
+ public VPaintableWidget getPaintable(Widget widget) {
+ return getPaintable(widget.getElement());
+ }
+
+ public void registerPaintable(String pid, VPaintable paintable) {
+ ComponentDetail componentDetail = GWT.create(ComponentDetail.class);
+ idToComponentDetail.put(pid, componentDetail);
+ idToPaintable.put(pid, paintable);
+ paintableToId.put(paintable, pid);
+ if (paintable instanceof VPaintableWidget) {
+ VPaintableWidget pw = (VPaintableWidget) paintable;
+ setPid(pw.getWidgetForPaintable().getElement(), pid);
+ }
+ }
+
+ private native void setPid(Element el, String pid)
+ /*-{
+ el.tkPid = pid;
+ }-*/;
+
+ /**
+ * Gets the paintableId for a specific paintable.
+ * <p>
+ * The paintableId is used in the UIDL to identify a specific widget
+ * instance, effectively linking the widget with it's server side Component.
+ * </p>
+ *
+ * @param paintable
+ * the paintable who's id is needed
+ * @return the id for the given paintable or null if the paintable could not
+ * be found
+ */
+ public String getPid(VPaintable paintable) {
+ if (paintable == null) {
+ return null;
+ }
+ return paintableToId.get(paintable);
+ }
+
+ @Deprecated
+ public String getPid(Widget widget) {
+ return getPid(widget.getElement());
+ }
+
+ /**
+ * Gets the paintableId using a DOM element - the element should be the main
+ * element for a paintable otherwise no id will be found. Use
+ * {@link #getPid(Paintable)} instead whenever possible.
+ *
+ * @see #getPid(Paintable)
+ * @param el
+ * element of the paintable whose pid is desired
+ * @return the pid of the element's paintable, if it's a paintable
+ */
+ native String getPid(Element el)
+ /*-{
+ return el.tkPid;
+ }-*/;
+
+ /**
+ * Gets the main element for the paintable with the given id. The revers of
+ * {@link #getPid(Element)}.
+ *
+ * @param pid
+ * the pid of the widget whose element is desired
+ * @return the element for the paintable corresponding to the pid
+ */
+ public Element getElement(String pid) {
+ VPaintable p = getPaintable(pid);
+ if (p instanceof VPaintableWidget) {
+ return ((VPaintableWidget) p).getWidgetForPaintable().getElement();
+ }
+
+ return null;
+ }
+
+ /**
+ * Unregisters the given paintable; always use after removing a paintable.
+ * This method does not remove the paintable from the DOM, but marks the
+ * paintable so that ApplicationConnection may clean up its references to
+ * it. Removing the widget from DOM is component containers responsibility.
+ *
+ * @param p
+ * the paintable to remove
+ */
+ public void unregisterPaintable(VPaintable p) {
+
+ // add to unregistry que
+
+ if (p == null) {
+ VConsole.error("WARN: Trying to unregister null paintable");
+ return;
+ }
+ String id = getPid(p);
+ Widget widget = null;
+ if (p instanceof VPaintableWidget) {
+ widget = ((VPaintableWidget) p).getWidgetForPaintable();
+ }
+
+ if (id == null) {
+ /*
+ * Uncomment the following to debug unregistring components. No
+ * paintables with null id should end here. At least one exception
+ * is our VScrollTableRow, that is hacked to fake it self as a
+ * Paintable to build support for sizing easier.
+ */
+ // if (!(p instanceof VScrollTableRow)) {
+ // VConsole.log("Trying to unregister Paintable not created by Application Connection.");
+ // }
+ } else {
+ unregistryBag.add(id);
+ }
+ if (widget != null && widget instanceof HasWidgets) {
+ unregisterChildPaintables((HasWidgets) widget);
+ }
+
+ }
+
+ void purgeUnregistryBag(boolean unregisterPaintables) {
+ if (unregisterPaintables) {
+ for (String pid : unregistryBag) {
+ VPaintable paintable = getPaintable(pid);
+ if (paintable == null) {
+ /*
+ * this should never happen, but it does :-( See e.g.
+ * com.vaadin.tests.components.accordion.RemoveTabs (with
+ * test script)
+ */
+ VConsole.error("Tried to unregister component (id="
+ + pid
+ + ") that is never registered (or already unregistered)");
+ continue;
+ }
+ Widget widget = null;
+ if (paintable instanceof VPaintableWidget) {
+ widget = ((VPaintableWidget) paintable)
+ .getWidgetForPaintable();
+ }
+
+ // check if can be cleaned
+ if (widget == null || !widget.isAttached()) {
+ // clean reference to paintable
+ idToComponentDetail.remove(pid);
+ idToPaintable.remove(pid);
+ paintableToId.remove(paintable);
+ }
+ /*
+ * else NOP : same component has been reattached to another
+ * parent or replaced by another component implementation.
+ */
+ }
+ }
+
+ unregistryBag.clear();
+ }
+
+ /**
+ * Unregisters a paintable and all it's child paintables recursively. Use
+ * when after removing a paintable that contains other paintables. Does not
+ * unregister the given container itself. Does not actually remove the
+ * paintable from the DOM.
+ *
+ * @see #unregisterPaintable(Paintable)
+ * @param container
+ */
+ public void unregisterChildPaintables(HasWidgets container) {
+ // FIXME: This should be based on the paintable hierarchy
+ final Iterator<Widget> it = container.iterator();
+ while (it.hasNext()) {
+ final Widget w = it.next();
+ VPaintableWidget p = getPaintable(w);
+ if (p != null) {
+ // This will unregister the paintable and all its children
+ unregisterPaintable(p);
+ } else if (w instanceof HasWidgets) {
+ // For normal widget containers, unregister the children
+ unregisterChildPaintables((HasWidgets) w);
+ }
+ }
+ }
+
+ /**
+ * FIXME: Should not be here
+ *
+ * @param pid
+ * @param uidl
+ */
+ @Deprecated
+ public void registerEventListenersFromUIDL(String pid, UIDL uidl) {
+ ComponentDetail cd = idToComponentDetail.get(pid);
+ if (cd == null) {
+ throw new IllegalArgumentException("Pid must not be null");
+ }
+
+ cd.registerEventListenersFromUIDL(uidl);
+
+ }
+
+ /**
+ * FIXME: Should not be here
+ *
+ * @param paintable
+ * @return
+ */
+ @Deprecated
+ public Size getOffsetSize(VPaintableWidget paintable) {
+ return getComponentDetail(paintable).getOffsetSize();
+ }
+
+ /**
+ * FIXME: Should not be here
+ *
+ * @param paintable
+ * @return
+ */
+ @Deprecated
+ public FloatSize getRelativeSize(VPaintableWidget paintable) {
+ return getComponentDetail(paintable).getRelativeSize();
+ }
+
+ /**
+ * FIXME: Should not be here
+ *
+ * @param paintable
+ * @return
+ */
+ @Deprecated
+ public void setOffsetSize(VPaintableWidget paintable, Size newSize) {
+ getComponentDetail(paintable).setOffsetSize(newSize);
+ }
+
+ /**
+ * FIXME: Should not be here
+ *
+ * @param paintable
+ * @return
+ */
+ @Deprecated
+ public void setRelativeSize(VPaintableWidget paintable,
+ FloatSize relativeSize) {
+ getComponentDetail(paintable).setRelativeSize(relativeSize);
+
+ }
+
+ private ComponentDetail getComponentDetail(VPaintableWidget paintable) {
+ return idToComponentDetail.get(getPid(paintable));
+ }
+
+ public int size() {
+ return idToPaintable.size();
+ }
+
+ /**
+ * FIXME: Should be moved to VAbstractPaintableWidget
+ *
+ * @param paintable
+ * @return
+ */
+ @Deprecated
+ public TooltipInfo getTooltipInfo(VPaintableWidget paintable, Object key) {
+ return getComponentDetail(paintable).getTooltipInfo(key);
+ }
+
+ @Deprecated
+ public TooltipInfo getWidgetTooltipInfo(Widget widget, Object key) {
+ return getTooltipInfo(getPaintable(widget), key);
+ }
+
+ public Collection<? extends VPaintable> getPaintables() {
+ return Collections.unmodifiableCollection(paintableToId.keySet());
+ }
+
+ /**
+ * FIXME: Should not be here
+ *
+ * @param paintable
+ * @return
+ */
+ @Deprecated
+ public void registerTooltip(VPaintableWidget paintable, Object key,
+ TooltipInfo tooltip) {
+ getComponentDetail(paintable).putAdditionalTooltip(key, tooltip);
+
+ }
+
+ /**
+ * FIXME: Should not be here
+ *
+ * @param paintable
+ * @return
+ */
+ @Deprecated
+ public boolean hasEventListeners(VPaintableWidget paintable,
+ String eventIdentifier) {
+ return getComponentDetail(paintable).hasEventListeners(eventIdentifier);
+ }
+
+ /**
+ * Tests if the widget is the root widget of a VPaintableWidget.
+ *
+ * @param widget
+ * The widget to test
+ * @return true if the widget is the root widget of a VPaintableWidget,
+ * false otherwise
+ */
+ public boolean isPaintable(Widget w) {
+ return getPid(w) != null;
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VPaintableWidget.java b/src/com/vaadin/terminal/gwt/client/VPaintableWidget.java
new file mode 100644
index 0000000000..11b6c9d0f6
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/VPaintableWidget.java
@@ -0,0 +1,31 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * An interface used by client-side widgets or paintable parts to receive
+ * updates from the corresponding server-side components in the form of
+ * {@link UIDL}.
+ *
+ * Updates can be sent back to the server using the
+ * {@link ApplicationConnection#updateVariable()} methods.
+ */
+public interface VPaintableWidget extends VPaintable {
+
+ /**
+ * TODO: Rename to getWidget
+ */
+ public Widget getWidgetForPaintable();
+
+ /**
+ * Returns the parent {@link VPaintableWidgetContainer}
+ *
+ * @return
+ */
+ // FIXME: Rename to getParent()
+ public VPaintableWidgetContainer getParentPaintable();
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VPaintableWidgetContainer.java b/src/com/vaadin/terminal/gwt/client/VPaintableWidgetContainer.java
new file mode 100644
index 0000000000..baf266546d
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/VPaintableWidgetContainer.java
@@ -0,0 +1,45 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.user.client.ui.HasWidgets;
+
+/**
+ * An interface used by client-side paintables whose widget is a component
+ * container (implements {@link HasWidgets}).
+ */
+public interface VPaintableWidgetContainer extends VPaintableWidget {
+
+ /**
+ * Update child components caption, description and error message.
+ *
+ * <p>
+ * Each component is responsible for maintaining its caption, description
+ * and error message. In most cases components doesn't want to do that and
+ * those elements reside outside of the component. Because of this layouts
+ * must provide service for it's childen to show those elements for them.
+ * </p>
+ *
+ * @param paintable
+ * Child component for which service is requested.
+ * @param uidl
+ * UIDL of the child component.
+ */
+ void updateCaption(VPaintableWidget paintable, UIDL uidl);
+
+ /**
+ * Returns the children for this paintable.
+ * <p>
+ * The children for this paintable are defined as all
+ * {@link VPaintableWidget}s whose parent is this
+ * {@link VPaintableWidgetContainer}.
+ * </p>
+ *
+ * @return A collection of children for this paintable. An empty collection
+ * if there are no children.
+ */
+ // public Collection<VPaintableWidget> getChildren();
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VTooltip.java b/src/com/vaadin/terminal/gwt/client/VTooltip.java
index ed8bd2eedd..0709fe531e 100644
--- a/src/com/vaadin/terminal/gwt/client/VTooltip.java
+++ b/src/com/vaadin/terminal/gwt/client/VTooltip.java
@@ -27,7 +27,7 @@ public class VTooltip extends VOverlay {
private static final int QUICK_OPEN_DELAY = 100;
VErrorMessage em = new VErrorMessage();
Element description = DOM.createDiv();
- private Paintable tooltipOwner;
+ private VPaintableWidget tooltipOwner;
private boolean closing = false;
private boolean opening = false;
@@ -110,7 +110,7 @@ public class VTooltip extends VOverlay {
}
}
- public void showTooltip(Paintable owner, Event event, Object key) {
+ public void showTooltip(VPaintableWidget owner, Event event, Object key) {
if (closing && tooltipOwner == owner && tooltipKey == key) {
// return to same tooltip, cancel closing
closeTimer.cancel();
@@ -207,7 +207,7 @@ public class VTooltip extends VOverlay {
}
- public void handleTooltipEvent(Event event, Paintable owner, Object key) {
+ public void handleTooltipEvent(Event event, VPaintableWidget owner, Object key) {
final int type = DOM.eventGetType(event);
if ((VTooltip.TOOLTIP_EVENTS & type) == type) {
if (type == Event.ONMOUSEOVER) {
diff --git a/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java b/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java
index 95d2fd0b5f..e63bcf98d9 100644
--- a/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java
+++ b/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java
@@ -24,8 +24,7 @@ import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ui.VUnknownComponent;
-import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.terminal.gwt.client.ui.VUnknownComponentPaintable;
import com.vaadin.terminal.gwt.client.ui.VWindow;
public class VUIDLBrowser extends SimpleTree {
@@ -98,14 +97,11 @@ public class VUIDLBrowser extends SimpleTree {
private String getNodeName(UIDL uidl, ApplicationConfiguration conf,
String name) {
- Class<? extends Paintable> widgetClassByDecodedTag = conf
+ Class<? extends VPaintableWidget> widgetClassByDecodedTag = conf
.getWidgetClassByEncodedTag(name);
- if (widgetClassByDecodedTag == VUnknownComponent.class) {
+ if (widgetClassByDecodedTag == VUnknownComponentPaintable.class) {
return conf.getUnknownServerClassNameByEncodedTagName(name)
+ "(NO CLIENT IMPLEMENTATION FOUND)";
- } else if (widgetClassByDecodedTag == VView.class
- && uidl.hasAttribute("sub")) {
- return "com.vaadin.terminal.gwt.ui.VWindow";
} else {
return widgetClassByDecodedTag.getName();
}
@@ -130,8 +126,8 @@ public class VUIDLBrowser extends SimpleTree {
// same
// host page
for (ApplicationConnection applicationConnection : runningApplications) {
- Paintable paintable = applicationConnection.getPaintable(uidl
- .getId());
+ VPaintableWidget paintable = (VPaintableWidget) VPaintableMap
+ .get(applicationConnection).getPaintable(uidl.getId());
highlight(paintable);
if (event != null && event.getNativeEvent().getShiftKey()) {
applicationConnection.highlightComponent(paintable);
@@ -201,7 +197,7 @@ public class VUIDLBrowser extends SimpleTree {
tmp.addItem(name + "=" + value);
}
if (tmp != null) {
- add(tmp);
+ add(tmp);
}
} catch (final Exception e) {
// Ignored, no variables
@@ -243,8 +239,8 @@ public class VUIDLBrowser extends SimpleTree {
}
}
- static void highlight(Paintable paintable) {
- Widget w = (Widget) paintable;
+ static void highlight(VPaintableWidget paintable) {
+ Widget w = paintable.getWidgetForPaintable();
if (w != null) {
Style style = highlight.getStyle();
style.setTop(w.getAbsoluteTop(), Unit.PX);
@@ -261,4 +257,4 @@ public class VUIDLBrowser extends SimpleTree {
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java b/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java
index a5c75d27dd..fef88c38bf 100644
--- a/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java
+++ b/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java
@@ -7,5 +7,5 @@ package com.vaadin.terminal.gwt.client;
* A helper class used by WidgetMap implementation. Used by the generated code.
*/
interface WidgetInstantiator {
- public Paintable get();
+ public VPaintableWidget get();
}
diff --git a/src/com/vaadin/terminal/gwt/client/WidgetMap.java b/src/com/vaadin/terminal/gwt/client/WidgetMap.java
index 51dac20132..3e02ad23ec 100644
--- a/src/com/vaadin/terminal/gwt/client/WidgetMap.java
+++ b/src/com/vaadin/terminal/gwt/client/WidgetMap.java
@@ -9,15 +9,21 @@ abstract class WidgetMap {
protected static HashMap<Class, WidgetInstantiator> instmap = new HashMap<Class, WidgetInstantiator>();
- public Paintable instantiate(Class<? extends Paintable> classType) {
+ // FIXME: Should use Paintable and not VPaintableWidget
+ public VPaintableWidget instantiate(
+ Class<? extends VPaintableWidget> classType) {
return instmap.get(classType).get();
}
- public abstract Class<? extends Paintable> getImplementationByServerSideClassName(
+ // FIXME: Should use Paintable and not VPaintableWidget
+ public abstract Class<? extends VPaintableWidget> getImplementationByServerSideClassName(
String fullyqualifiedName);
- public abstract Class<? extends Paintable>[] getDeferredLoadedWidgets();
+ // FIXME: Should use Paintable and not VPaintableWidget
+ public abstract Class<? extends VPaintableWidget>[] getDeferredLoadedWidgets();
- public abstract void ensureInstantiator(Class<? extends Paintable> classType);
+ // FIXME: Should use Paintable and not VPaintableWidget
+ public abstract void ensureInstantiator(
+ Class<? extends VPaintableWidget> classType);
}
diff --git a/src/com/vaadin/terminal/gwt/client/WidgetSet.java b/src/com/vaadin/terminal/gwt/client/WidgetSet.java
index fb77775549..390d79ce17 100644
--- a/src/com/vaadin/terminal/gwt/client/WidgetSet.java
+++ b/src/com/vaadin/terminal/gwt/client/WidgetSet.java
@@ -6,18 +6,9 @@ package com.vaadin.terminal.gwt.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ui.VButton;
-import com.vaadin.terminal.gwt.client.ui.VCheckBox;
-import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
-import com.vaadin.terminal.gwt.client.ui.VListSelect;
-import com.vaadin.terminal.gwt.client.ui.VPasswordField;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical;
-import com.vaadin.terminal.gwt.client.ui.VTextArea;
-import com.vaadin.terminal.gwt.client.ui.VTextField;
-import com.vaadin.terminal.gwt.client.ui.VUnknownComponent;
-import com.vaadin.terminal.gwt.client.ui.VView;
-import com.vaadin.terminal.gwt.client.ui.VWindow;
+import com.vaadin.terminal.gwt.client.ui.VFilterSelectPaintable;
+import com.vaadin.terminal.gwt.client.ui.VListSelectPaintable;
+import com.vaadin.terminal.gwt.client.ui.VUnknownComponentPaintable;
public class WidgetSet {
@@ -30,7 +21,8 @@ public class WidgetSet {
/**
* Create an uninitialized component that best matches given UIDL. The
- * component must be a {@link Widget} that implements {@link Paintable}.
+ * component must be a {@link Widget} that implements
+ * {@link VPaintableWidget}.
*
* @param uidl
* UIDL to be painted with returned component.
@@ -40,7 +32,8 @@ public class WidgetSet {
* @return New uninitialized and unregistered component that can paint given
* UIDL.
*/
- public Paintable createWidget(UIDL uidl, ApplicationConfiguration conf) {
+ public VPaintableWidget createWidget(UIDL uidl,
+ ApplicationConfiguration conf) {
/*
* Yes, this (including the generated code in WidgetMap) may look very
* odd code, but due the nature of GWT, we cannot do this any cleaner.
@@ -51,16 +44,15 @@ public class WidgetSet {
* TODO should try to get rid of these exceptions here
*/
- final Class<? extends Paintable> classType = resolveWidgetType(uidl,
- conf);
- if (classType == null || classType == VUnknownComponent.class) {
+ final Class<? extends VPaintableWidget> classType = resolveWidgetType(
+ uidl, conf);
+ if (classType == null || classType == VUnknownComponentPaintable.class) {
String serverSideName = conf
.getUnknownServerClassNameByEncodedTagName(uidl.getTag());
- VUnknownComponent c = GWT.create(VUnknownComponent.class);
+ VUnknownComponentPaintable c = GWT
+ .create(VUnknownComponentPaintable.class);
c.setServerSideClassName(serverSideName);
return c;
- } else if (VWindow.class == classType) {
- return GWT.create(VWindow.class);
} else {
/*
* let the auto generated code instantiate this type
@@ -70,37 +62,23 @@ public class WidgetSet {
}
- protected Class<? extends Paintable> resolveWidgetType(UIDL uidl,
+ protected Class<? extends VPaintableWidget> resolveWidgetType(UIDL uidl,
ApplicationConfiguration conf) {
final String tag = uidl.getTag();
- Class<? extends Paintable> widgetClass = conf
+ Class<? extends VPaintableWidget> widgetClass = conf
.getWidgetClassByEncodedTag(tag);
// add our historical quirks
- if (widgetClass == VButton.class && uidl.hasAttribute("type")) {
- return VCheckBox.class;
- } else if (widgetClass == VView.class && uidl.hasAttribute("sub")) {
- return VWindow.class;
- } else if (widgetClass == VFilterSelect.class) {
+ if (widgetClass == VFilterSelectPaintable.class) {
if (uidl.hasAttribute("type")) {
final String type = uidl.getStringAttribute("type").intern();
if ("legacy-multi" == type) {
- return VListSelect.class;
+ return VListSelectPaintable.class;
}
}
- } else if (widgetClass == VTextField.class) {
- if (uidl.hasAttribute("multiline")) {
- return VTextArea.class;
- } else if (uidl.hasAttribute("secret")) {
- return VPasswordField.class;
- }
- } else if (widgetClass == VSplitPanelHorizontal.class
- && uidl.hasAttribute("vertical")) {
- return VSplitPanelVertical.class;
}
-
return widgetClass;
}
@@ -129,12 +107,12 @@ public class WidgetSet {
* @param applicationConfiguration
* @return
*/
- public Class<? extends Paintable> getImplementationByClassName(
+ public Class<? extends VPaintableWidget> getImplementationByClassName(
String fullyqualifiedName) {
if (fullyqualifiedName == null) {
- return VUnknownComponent.class;
+ return VUnknownComponentPaintable.class;
}
- Class<? extends Paintable> implementationByServerSideClassName = widgetMap
+ Class<? extends VPaintableWidget> implementationByServerSideClassName = widgetMap
.getImplementationByServerSideClassName(fullyqualifiedName);
/*
@@ -143,26 +121,19 @@ public class WidgetSet {
* is in multiselect mode, causing the clientside implementation to
* *actually* be VListSelect, when the annotation says VFilterSelect
*/
- if (fullyqualifiedName.equals("com.vaadin.ui.Button")) {
- loadImplementation(VCheckBox.class);
- } else if (fullyqualifiedName.equals("com.vaadin.ui.Select")) {
- loadImplementation(VListSelect.class);
- } else if (fullyqualifiedName.equals("com.vaadin.ui.TextField")) {
- loadImplementation(VTextArea.class);
- loadImplementation(VPasswordField.class);
- } else if (fullyqualifiedName.equals("com.vaadin.ui.SplitPanel")) {
- loadImplementation(VSplitPanelVertical.class);
+ if (fullyqualifiedName.equals("com.vaadin.ui.Select")) {
+ loadImplementation(VListSelectPaintable.class);
}
return implementationByServerSideClassName;
}
- public Class<? extends Paintable>[] getDeferredLoadedWidgets() {
+ public Class<? extends VPaintableWidget>[] getDeferredLoadedWidgets() {
return widgetMap.getDeferredLoadedWidgets();
}
- public void loadImplementation(Class<? extends Paintable> nextType) {
+ public void loadImplementation(Class<? extends VPaintableWidget> nextType) {
widgetMap.ensureInstantiator(nextType);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
index 3deb140d30..c272f0ea75 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
@@ -17,10 +17,10 @@ import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
public abstract class ClickEventHandler implements DoubleClickHandler,
ContextMenuHandler, MouseUpHandler {
@@ -30,10 +30,11 @@ public abstract class ClickEventHandler implements DoubleClickHandler,
private HandlerRegistration contextMenuHandlerRegistration;
protected String clickEventIdentifier;
- protected Paintable paintable;
+ protected VPaintableWidget paintable;
private ApplicationConnection client;
- public ClickEventHandler(Paintable paintable, String clickEventIdentifier) {
+ public ClickEventHandler(VPaintableWidget paintable,
+ String clickEventIdentifier) {
this.paintable = paintable;
this.clickEventIdentifier = clickEventIdentifier;
}
@@ -81,7 +82,8 @@ public abstract class ClickEventHandler implements DoubleClickHandler,
protected void fireClick(NativeEvent event) {
ApplicationConnection client = getApplicationConnection();
- String pid = getApplicationConnection().getPid(paintable);
+ String pid = VPaintableMap.get(getApplicationConnection()).getPid(
+ paintable);
MouseEventDetails mouseDetails = new MouseEventDetails(event,
getRelativeToElement());
@@ -126,11 +128,7 @@ public abstract class ClickEventHandler implements DoubleClickHandler,
* or null if no relative coordinates can be calculated.
*/
protected Element getRelativeToElement() {
- if (paintable instanceof Widget) {
- return ((Widget) paintable).getElement();
- }
-
- return null;
+ return paintable.getWidgetForPaintable().getElement();
}
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java
index 1b97406ae0..4984c4ce3b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java
@@ -13,11 +13,9 @@ import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.impl.FocusImpl;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
/**
* A panel that contains an always visible 0x0 size element that holds the focus
- * for all browsers but IE6.
*/
public class FocusElementPanel extends SimpleFocusablePanel {
@@ -30,22 +28,20 @@ public class FocusElementPanel extends SimpleFocusablePanel {
@Override
public void setWidget(Widget w) {
super.setWidget(w);
- if (!BrowserInfo.get().isIE6()) {
- if (focusElement.getParentElement() == null) {
- Style style = focusElement.getStyle();
- style.setPosition(Position.FIXED);
- style.setTop(0, Unit.PX);
- style.setLeft(0, Unit.PX);
- getElement().appendChild(focusElement);
- /* Sink from focusElement too as focus and blur don't bubble */
- DOM.sinkEvents(
- (com.google.gwt.user.client.Element) focusElement
- .cast(), Event.FOCUSEVENTS);
- // revert to original, not focusable
- getElement().setPropertyObject("tabIndex", null);
- } else {
- moveFocusElementAfterWidget();
- }
+ if (focusElement.getParentElement() == null) {
+ Style style = focusElement.getStyle();
+ style.setPosition(Position.FIXED);
+ style.setTop(0, Unit.PX);
+ style.setLeft(0, Unit.PX);
+ getElement().appendChild(focusElement);
+ /* Sink from focusElement too as focus and blur don't bubble */
+ DOM.sinkEvents(
+ (com.google.gwt.user.client.Element) focusElement.cast(),
+ Event.FOCUSEVENTS);
+ // revert to original, not focusable
+ getElement().setPropertyObject("tabIndex", null);
+ } else {
+ moveFocusElementAfterWidget();
}
}
@@ -58,28 +54,20 @@ public class FocusElementPanel extends SimpleFocusablePanel {
@Override
public void setFocus(boolean focus) {
- if (BrowserInfo.get().isIE6()) {
- super.setFocus(focus);
+ if (focus) {
+ FocusImpl.getFocusImplForPanel().focus(
+ (Element) focusElement.cast());
} else {
- if (focus) {
- FocusImpl.getFocusImplForPanel().focus(
- (Element) focusElement.cast());
- } else {
- FocusImpl.getFocusImplForPanel().blur(
- (Element) focusElement.cast());
- }
+ FocusImpl.getFocusImplForPanel()
+ .blur((Element) focusElement.cast());
}
}
@Override
public void setTabIndex(int tabIndex) {
- if (BrowserInfo.get().isIE6()) {
- super.setTabIndex(tabIndex);
- } else {
- getElement().setTabIndex(-1);
- if (focusElement != null) {
- focusElement.setTabIndex(tabIndex);
- }
+ getElement().setTabIndex(-1);
+ if (focusElement != null) {
+ focusElement.setTabIndex(tabIndex);
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
index 1025752ca9..6b22f3c9f3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
@@ -21,7 +21,6 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.impl.FocusImpl;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
/**
* A scrollhandlers similar to {@link ScrollPanel}.
@@ -57,18 +56,9 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
if (useFakeFocusElement()) {
if (focusElement.getParentElement() == null) {
Style style = focusElement.getStyle();
- if (BrowserInfo.get().isIE6()) {
- style.setOverflow(Overflow.HIDDEN);
- style.setHeight(0, Unit.PX);
- style.setWidth(0, Unit.PX);
- style.setPosition(Position.ABSOLUTE);
-
- addScrollHandler(this);
- } else {
- style.setPosition(Position.FIXED);
- style.setTop(0, Unit.PX);
- style.setLeft(0, Unit.PX);
- }
+ style.setPosition(Position.FIXED);
+ style.setTop(0, Unit.PX);
+ style.setLeft(0, Unit.PX);
getElement().appendChild(focusElement);
/* Sink from focusElemet too as focusa and blur don't bubble */
DOM.sinkEvents(
diff --git a/src/com/vaadin/terminal/gwt/client/ui/Icon.java b/src/com/vaadin/terminal/gwt/client/ui/Icon.java
index fd2229fc8d..b64605aac9 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/Icon.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/Icon.java
@@ -19,7 +19,6 @@ public class Icon extends UIObject {
DOM.setElementProperty(getElement(), "alt", "");
setStyleName(CLASSNAME);
this.client = client;
- client.addPngFix(getElement());
}
public Icon(ApplicationConnection client, String uidlUri) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java
index 3a4048907f..896b992afc 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java
@@ -10,25 +10,27 @@ import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.user.client.Element;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
public abstract class LayoutClickEventHandler extends ClickEventHandler {
- public LayoutClickEventHandler(Paintable paintable,
+ public LayoutClickEventHandler(VPaintableWidget paintable,
String clickEventIdentifier) {
super(paintable, clickEventIdentifier);
}
- protected abstract Paintable getChildComponent(Element element);
+ protected abstract VPaintableWidget getChildComponent(Element element);
@Override
protected void fireClick(NativeEvent event) {
ApplicationConnection client = getApplicationConnection();
- String pid = getApplicationConnection().getPid(paintable);
+ String pid = VPaintableMap.get(getApplicationConnection()).getPid(
+ paintable);
MouseEventDetails mouseDetails = new MouseEventDetails(event,
getRelativeToElement());
- Paintable childComponent = getChildComponent((Element) event
+ VPaintableWidget childComponent = getChildComponent((Element) event
.getEventTarget().cast());
Map<String, Object> parameters = new HashMap<String, Object>();
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java b/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java
index 934fcaa8b7..2bd578a45d 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java
@@ -15,13 +15,12 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.KeyboardListenerCollection;
-import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea;
/**
@@ -52,12 +51,12 @@ public class ShortcutActionHandler {
}
/**
- * A focusable {@link Paintable} implementing this interface will be
+ * A focusable {@link VPaintableWidget} implementing this interface will be
* notified before shortcut actions are handled if it will be the target of
* the action (most commonly means it is the focused component during the
* keyboard combination is triggered by the user).
*/
- public interface BeforeShortcutActionListener extends Paintable {
+ public interface BeforeShortcutActionListener extends VPaintableWidget {
/**
* This method is called by ShortcutActionHandler before firing the
* shortcut if the Paintable is currently focused (aka the target of the
@@ -111,7 +110,7 @@ public class ShortcutActionHandler {
}
}
- public void handleKeyboardEvent(final Event event, Paintable target) {
+ public void handleKeyboardEvent(final Event event, VPaintableWidget target) {
final int modifiers = KeyboardListenerCollection
.getKeyboardModifiers(event);
final char keyCode = (char) DOM.eventGetKeyCode(event);
@@ -133,16 +132,12 @@ public class ShortcutActionHandler {
}
private void fireAction(final Event event, final ShortcutAction a,
- Paintable target) {
+ VPaintableWidget target) {
final Element et = DOM.eventGetTarget(event);
if (target == null) {
- Widget w = Util.findWidget(et, null);
- while (w != null && !(w instanceof Paintable)) {
- w = w.getParent();
- }
- target = (Paintable) w;
+ target = Util.findPaintable(client, et);
}
- final Paintable finalTarget = target;
+ final VPaintableWidget finalTarget = target;
event.preventDefault();
diff --git a/src/com/vaadin/terminal/gwt/client/ui/Table.java b/src/com/vaadin/terminal/gwt/client/ui/Table.java
index 4b3ba0422e..018200ab05 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/Table.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/Table.java
@@ -5,9 +5,9 @@
package com.vaadin.terminal.gwt.client.ui;
import com.google.gwt.user.client.ui.HasWidgets;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
-public interface Table extends Paintable, HasWidgets {
+public interface Table extends VPaintableWidget, HasWidgets {
final int SELECT_MODE_NONE = 0;
final int SELECT_MODE_SINGLE = 1;
final int SELECT_MODE_MULTI = 2;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java
index a6abc411f8..f95acfc43c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java
@@ -4,7 +4,6 @@
package com.vaadin.terminal.gwt.client.ui;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
@@ -13,24 +12,19 @@ import java.util.Set;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style;
-import com.google.gwt.event.dom.client.DomEvent.Type;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
-import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
public class VAbsoluteLayout extends ComplexPanel implements Container {
@@ -50,26 +44,11 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
private Object previousStyleName;
- private Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>();
+ Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>();
protected ApplicationConnection client;
- private boolean rendering;
-
- private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
- this, EventId.LAYOUT_CLICK) {
-
- @Override
- protected Paintable getChildComponent(Element element) {
- return getComponent(element);
- }
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
- };
+ boolean rendering;
public VAbsoluteLayout() {
setElement(Document.get().createDivElement());
@@ -132,52 +111,13 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
}
}
- public boolean requestLayout(Set<Paintable> children) {
+ public boolean requestLayout(Set<Widget> children) {
// component inside an absolute panel never affects parent nor the
// layout
return true;
}
- public void updateCaption(Paintable component, UIDL uidl) {
- AbsoluteWrapper parent2 = (AbsoluteWrapper) ((Widget) component)
- .getParent();
- parent2.updateCaption(uidl);
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
- this.client = client;
- // TODO margin handling
- if (client.updateComponent(this, uidl, true)) {
- rendering = false;
- return;
- }
-
- clickEventHandler.handleEventHandlerRegistration(client);
-
- HashSet<String> unrenderedPids = new HashSet<String>(
- pidToComponentWrappper.keySet());
-
- for (Iterator<Object> childIterator = uidl.getChildIterator(); childIterator
- .hasNext();) {
- UIDL cc = (UIDL) childIterator.next();
- if (cc.getTag().equals("cc")) {
- UIDL componentUIDL = cc.getChildUIDL(0);
- unrenderedPids.remove(componentUIDL.getId());
- getWrapper(client, componentUIDL).updateFromUIDL(cc);
- }
- }
-
- for (String pid : unrenderedPids) {
- AbsoluteWrapper absoluteWrapper = pidToComponentWrappper.get(pid);
- pidToComponentWrappper.remove(pid);
- absoluteWrapper.destroy();
- }
- rendering = false;
- }
-
- private AbsoluteWrapper getWrapper(ApplicationConnection client,
- UIDL componentUIDL) {
+ AbsoluteWrapper getWrapper(ApplicationConnection client, UIDL componentUIDL) {
AbsoluteWrapper wrapper = pidToComponentWrappper.get(componentUIDL
.getId());
if (wrapper == null) {
@@ -211,9 +151,6 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
canvas.getStyle().setProperty("width", width);
if (!rendering) {
- if (BrowserInfo.get().isIE6()) {
- relayoutWrappersForIe6();
- }
relayoutRelativeChildren();
}
}
@@ -236,21 +173,10 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
canvas.getStyle().setProperty("height", height);
if (!rendering) {
- if (BrowserInfo.get().isIE6()) {
- relayoutWrappersForIe6();
- }
relayoutRelativeChildren();
}
}
- private void relayoutWrappersForIe6() {
- for (Widget wrapper : getChildren()) {
- if (wrapper instanceof AbsoluteWrapper) {
- ((AbsoluteWrapper) wrapper).ie6Layout();
- }
- }
- }
-
public class AbsoluteWrapper extends SimplePanel {
private String css;
private String left;
@@ -259,10 +185,10 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
private String bottom;
private String zIndex;
- private Paintable paintable;
+ private VPaintableWidget paintable;
private VCaption caption;
- public AbsoluteWrapper(Paintable paintable) {
+ public AbsoluteWrapper(VPaintableWidget paintable) {
this.paintable = paintable;
setStyleName(CLASSNAME + "-wrapper");
}
@@ -288,7 +214,7 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
@Override
public void setWidget(Widget w) {
// this fixes #5457 (Widget implementation can change on-the-fly)
- paintable = (Paintable) w;
+ paintable = VPaintableMap.get(client).getPaintable(w);
super.setWidget(w);
}
@@ -302,8 +228,8 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
public void updateFromUIDL(UIDL componentUIDL) {
setPosition(componentUIDL.getStringAttribute("css"));
- if (getWidget() != paintable) {
- setWidget((Widget) paintable);
+ if (getWidget() != paintable.getWidgetForPaintable()) {
+ setWidget(paintable.getWidgetForPaintable());
}
UIDL childUIDL = componentUIDL.getChildUIDL(0);
paintable.updateFromUIDL(childUIDL, client);
@@ -311,7 +237,8 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
// child may need relative size adjustment if wrapper details
// have changed this could be optimized (check if wrapper size
// has changed)
- client.handleComponentRelativeSize((Widget) paintable);
+ client.handleComponentRelativeSize(paintable
+ .getWidgetForPaintable());
}
}
@@ -353,9 +280,6 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
style.setProperty("right", right);
style.setProperty("bottom", bottom);
- if (BrowserInfo.get().isIE6()) {
- ie6Layout();
- }
}
updateCaptionPosition();
}
@@ -369,60 +293,6 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
- caption.getHeight());
}
}
-
- private void ie6Layout() {
- // special handling for IE6 is needed, it does not support
- // setting both left/right or top/bottom
- Style style = getElement().getStyle();
- if (bottom != null && top != null) {
- // define height for wrapper to simulate bottom property
- int bottompixels = measureForIE6(bottom, true);
- VConsole.log("ALB" + bottompixels);
- int height = canvas.getOffsetHeight() - bottompixels
- - getElement().getOffsetTop();
- VConsole.log("ALB" + height);
- if (height < 0) {
- height = 0;
- }
- style.setPropertyPx("height", height);
- } else {
- // reset possibly existing value
- style.setProperty("height", "");
- }
- if (left != null && right != null) {
- // define width for wrapper to simulate right property
- int rightPixels = measureForIE6(right, false);
- VConsole.log("ALR" + rightPixels);
- int width = canvas.getOffsetWidth() - rightPixels
- - getElement().getOffsetLeft();
- VConsole.log("ALR" + width);
- if (width < 0) {
- width = 0;
- }
- style.setPropertyPx("width", width);
- } else {
- // reset possibly existing value
- style.setProperty("width", "");
- }
- }
-
- }
-
- private Element measureElement;
-
- private int measureForIE6(String cssLength, boolean vertical) {
- if (measureElement == null) {
- measureElement = DOM.createDiv();
- measureElement.getStyle().setProperty("position", "absolute");
- canvas.appendChild(measureElement);
- }
- if (vertical) {
- measureElement.getStyle().setProperty("height", cssLength);
- return measureElement.getOffsetHeight();
- } else {
- measureElement.getStyle().setProperty("width", cssLength);
- return measureElement.getOffsetWidth();
- }
}
/**
@@ -435,8 +305,12 @@ public class VAbsoluteLayout extends ComplexPanel implements Container {
* @return The Paintable which the element is a part of. Null if the element
* belongs to the layout and not to a child.
*/
- private Paintable getComponent(Element element) {
+ VPaintableWidget getComponent(Element element) {
return Util.getPaintableForElement(client, this, element);
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayoutPaintable.java
new file mode 100644
index 0000000000..9a0b6eacf6
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayoutPaintable.java
@@ -0,0 +1,84 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.EventId;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout.AbsoluteWrapper;
+
+public class VAbsoluteLayoutPaintable extends VAbstractPaintableWidgetContainer {
+
+ private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
+ this, EventId.LAYOUT_CLICK) {
+
+ @Override
+ protected VPaintableWidget getChildComponent(Element element) {
+ return getWidgetForPaintable().getComponent(element);
+ }
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ };
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+ getWidgetForPaintable().client = client;
+ // TODO margin handling
+ if (client.updateComponent(this, uidl, true)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ HashSet<String> unrenderedPids = new HashSet<String>(
+ getWidgetForPaintable().pidToComponentWrappper.keySet());
+
+ for (Iterator<Object> childIterator = uidl.getChildIterator(); childIterator
+ .hasNext();) {
+ UIDL cc = (UIDL) childIterator.next();
+ if (cc.getTag().equals("cc")) {
+ UIDL componentUIDL = cc.getChildUIDL(0);
+ unrenderedPids.remove(componentUIDL.getId());
+ getWidgetForPaintable().getWrapper(client, componentUIDL)
+ .updateFromUIDL(cc);
+ }
+ }
+
+ for (String pid : unrenderedPids) {
+ AbsoluteWrapper absoluteWrapper = getWidgetForPaintable().pidToComponentWrappper
+ .get(pid);
+ getWidgetForPaintable().pidToComponentWrappper.remove(pid);
+ absoluteWrapper.destroy();
+ }
+ getWidgetForPaintable().rendering = false;
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ AbsoluteWrapper parent2 = (AbsoluteWrapper) (component
+ .getWidgetForPaintable()).getParent();
+ parent2.updateCaption(uidl);
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VAbsoluteLayout.class);
+ }
+
+ @Override
+ public VAbsoluteLayout getWidgetForPaintable() {
+ return (VAbsoluteLayout) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java b/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java
new file mode 100644
index 0000000000..09bf02ec43
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java
@@ -0,0 +1,103 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.VPaintableWidgetContainer;
+
+public abstract class VAbstractPaintableWidget implements VPaintableWidget {
+
+ private Widget widget;
+ private ApplicationConnection connection;
+ private String id;
+
+ /* State variables */
+ private boolean enabled = true;
+
+ /**
+ * Default constructor
+ */
+ public VAbstractPaintableWidget() {
+ }
+
+ /**
+ * Called after the application connection reference has been set up
+ */
+ public void init() {
+ }
+
+ /**
+ * Creates and returns the widget for this VPaintableWidget. This method
+ * should only be called once when initializing the paintable.
+ *
+ * @return
+ */
+ protected abstract Widget createWidget();
+
+ /**
+ * Returns the widget associated with this paintable. The widget returned by
+ * this method must not changed during the life time of the paintable.
+ *
+ * @return The widget associated with this paintable
+ */
+ public Widget getWidgetForPaintable() {
+ if (widget == null) {
+ widget = createWidget();
+ }
+
+ return widget;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.terminal.gwt.client.VPaintable#getConnection()
+ */
+ public final ApplicationConnection getConnection() {
+ return connection;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.VPaintable#setConnection(com.vaadin.terminal
+ * .gwt.client.ApplicationConnection)
+ */
+ public final void setConnection(ApplicationConnection connection) {
+ this.connection = connection;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public VPaintableWidgetContainer getParentPaintable() {
+ // FIXME: Return VPaintableWidgetContainer
+ // FIXME: Store hierarchy instead of doing lookup every time
+
+ VPaintableMap paintableMap = VPaintableMap.get(getConnection());
+
+ Widget w = getWidgetForPaintable();
+ while (w != null) {
+ w = w.getParent();
+ if (paintableMap.isPaintable(w)) {
+ return (VPaintableWidgetContainer) paintableMap.getPaintable(w);
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidgetContainer.java b/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidgetContainer.java
new file mode 100644
index 0000000000..1f78c02f58
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidgetContainer.java
@@ -0,0 +1,17 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.vaadin.terminal.gwt.client.VPaintableWidgetContainer;
+
+public abstract class VAbstractPaintableWidgetContainer extends
+ VAbstractPaintableWidget implements VPaintableWidgetContainer {
+
+ /**
+ * Default constructor
+ */
+ public VAbstractPaintableWidgetContainer() {
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java
index 8715cfffca..1aa9d92770 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java
@@ -6,10 +6,7 @@ package com.vaadin.terminal.gwt.client.ui;
import java.util.Set;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
-import com.google.gwt.event.dom.client.DomEvent.Type;
import com.google.gwt.event.dom.client.TouchCancelEvent;
import com.google.gwt.event.dom.client.TouchCancelHandler;
import com.google.gwt.event.dom.client.TouchEndEvent;
@@ -18,9 +15,6 @@ import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchMoveHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchStartHandler;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -30,62 +24,18 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation;
import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
-public class VSplitPanel extends ComplexPanel implements Container,
+public class VAbstractSplitPanel extends ComplexPanel implements Container,
ContainerResizedListener {
private boolean enabled = false;
public static final String CLASSNAME = "v-splitpanel";
- public static final String SPLITTER_CLICK_EVENT_IDENTIFIER = "sp_click";
-
- private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
- SPLITTER_CLICK_EVENT_IDENTIFIER) {
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- if ((Event.getEventsSunk(splitter) & Event.getTypeInt(type
- .getName())) != 0) {
- // If we are already sinking the event for the splitter we do
- // not want to additionally sink it for the root element
- return addHandler(handler, type);
- } else {
- return addDomHandler(handler, type);
- }
- }
-
- @Override
- public void onContextMenu(
- com.google.gwt.event.dom.client.ContextMenuEvent event) {
- Element target = event.getNativeEvent().getEventTarget().cast();
- if (splitter.isOrHasChild(target)) {
- super.onContextMenu(event);
- }
- };
-
- @Override
- protected void fireClick(NativeEvent event) {
- Element target = event.getEventTarget().cast();
- if (splitter.isOrHasChild(target)) {
- super.fireClick(event);
- }
- }
-
- @Override
- protected Element getRelativeToElement() {
- return null;
- }
-
- };
-
public static final int ORIENTATION_HORIZONTAL = 0;
public static final int ORIENTATION_VERTICAL = 1;
@@ -94,9 +44,9 @@ public class VSplitPanel extends ComplexPanel implements Container,
private int orientation = ORIENTATION_HORIZONTAL;
- private Widget firstChild;
+ Widget firstChild;
- private Widget secondChild;
+ Widget secondChild;
private final Element wrapper = DOM.createDiv();
@@ -104,7 +54,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
private final Element secondContainer = DOM.createDiv();
- private final Element splitter = DOM.createDiv();
+ final Element splitter = DOM.createDiv();
private boolean resizing;
@@ -122,11 +72,11 @@ public class VSplitPanel extends ComplexPanel implements Container,
private boolean positionReversed = false;
- private String[] componentStyleNames;
+ String[] componentStyleNames;
private Element draggingCurtain;
- private ApplicationConnection client;
+ ApplicationConnection client;
private String width = "";
@@ -137,14 +87,14 @@ public class VSplitPanel extends ComplexPanel implements Container,
RenderInformation renderInformation = new RenderInformation();
- private String id;
+ String id;
- private boolean immediate;
+ boolean immediate;
- private boolean rendering = false;
+ boolean rendering = false;
/* The current position of the split handle in either percentages or pixels */
- private String position;
+ String position;
protected Element scrolledContainer;
@@ -152,11 +102,11 @@ public class VSplitPanel extends ComplexPanel implements Container,
private TouchScrollDelegate touchScrollDelegate;
- public VSplitPanel() {
+ public VAbstractSplitPanel() {
this(ORIENTATION_HORIZONTAL);
}
- public VSplitPanel(int orientation) {
+ public VAbstractSplitPanel(int orientation) {
setElement(DOM.createDiv());
switch (orientation) {
case ORIENTATION_HORIZONTAL:
@@ -256,73 +206,6 @@ public class VSplitPanel extends ComplexPanel implements Container,
+ "-second-container");
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
- id = uidl.getId();
- rendering = true;
-
- immediate = uidl.hasAttribute("immediate");
-
- if (client.updateComponent(this, uidl, true)) {
- rendering = false;
- return;
- }
- setEnabled(!uidl.getBooleanAttribute("disabled"));
-
- clickEventHandler.handleEventHandlerRegistration(client);
- if (uidl.hasAttribute("style")) {
- componentStyleNames = uidl.getStringAttribute("style").split(" ");
- } else {
- componentStyleNames = new String[0];
- }
-
- setLocked(uidl.getBooleanAttribute("locked"));
-
- setPositionReversed(uidl.getBooleanAttribute("reversed"));
-
- setStylenames();
-
- position = uidl.getStringAttribute("position");
- setSplitPosition(position);
-
- final Paintable newFirstChild = client.getPaintable(uidl
- .getChildUIDL(0));
- final Paintable newSecondChild = client.getPaintable(uidl
- .getChildUIDL(1));
- if (firstChild != newFirstChild) {
- if (firstChild != null) {
- client.unregisterPaintable((Paintable) firstChild);
- }
- setFirstWidget((Widget) newFirstChild);
- }
- if (secondChild != newSecondChild) {
- if (secondChild != null) {
- client.unregisterPaintable((Paintable) secondChild);
- }
- setSecondWidget((Widget) newSecondChild);
- }
- newFirstChild.updateFromUIDL(uidl.getChildUIDL(0), client);
- newSecondChild.updateFromUIDL(uidl.getChildUIDL(1), client);
-
- renderInformation.updateSize(getElement());
-
- if (BrowserInfo.get().isIE7()) {
- // Part III of IE7 hack
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- iLayout();
- }
- });
- }
-
- // This is needed at least for cases like #3458 to take
- // appearing/disappearing scrollbars into account.
- client.runDescendentsLayout(this);
-
- rendering = false;
-
- }
-
@Override
public boolean remove(Widget w) {
boolean removed = super.remove(w);
@@ -336,7 +219,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
return removed;
}
- private void setLocked(boolean newValue) {
+ void setLocked(boolean newValue) {
if (locked != newValue) {
locked = newValue;
splitterSize = -1;
@@ -344,7 +227,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
}
}
- private void setPositionReversed(boolean reversed) {
+ void setPositionReversed(boolean reversed) {
if (positionReversed != reversed) {
if (orientation == ORIENTATION_HORIZONTAL) {
DOM.setStyleAttribute(splitter, "right", "");
@@ -358,7 +241,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
}
}
- private void setSplitPosition(String pos) {
+ void setSplitPosition(String pos) {
if (pos == null) {
return;
}
@@ -478,7 +361,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
}
- private void setFirstWidget(Widget w) {
+ void setFirstWidget(Widget w) {
if (firstChild != null) {
firstChild.removeFromParent();
}
@@ -486,7 +369,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
firstChild = w;
}
- private void setSecondWidget(Widget w) {
+ void setSecondWidget(Widget w) {
if (secondChild != null) {
secondChild.removeFromParent();
}
@@ -773,11 +656,11 @@ public class VSplitPanel extends ComplexPanel implements Container,
}
}
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
// content size change might cause change to its available space
// (scrollbars)
- for (Paintable paintable : child) {
- client.handleComponentRelativeSize((Widget) paintable);
+ for (Widget widget : children) {
+ client.handleComponentRelativeSize(widget);
}
if (height != null && width != null) {
/*
@@ -796,10 +679,6 @@ public class VSplitPanel extends ComplexPanel implements Container,
}
- public void updateCaption(Paintable component, UIDL uidl) {
- // TODO Implement caption handling
- }
-
/**
* Updates the new split position back to server.
*/
@@ -815,7 +694,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
client.updateVariable(id, "position", pos, immediate);
}
- private void setStylenames() {
+ void setStylenames() {
final String splitterSuffix = (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter"
: "-vsplitter");
final String firstContainerSuffix = "-first-container";
@@ -850,4 +729,8 @@ public class VSplitPanel extends ComplexPanel implements Container,
public boolean isEnabled() {
return enabled;
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanelPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanelPaintable.java
new file mode 100644
index 0000000000..84c3ab5221
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanelPaintable.java
@@ -0,0 +1,140 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public abstract class VAbstractSplitPanelPaintable extends
+ VAbstractPaintableWidgetContainer {
+
+ public static final String SPLITTER_CLICK_EVENT_IDENTIFIER = "sp_click";
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ // TODO Implement caption handling
+ }
+
+ ClickEventHandler clickEventHandler = new ClickEventHandler(this,
+ SPLITTER_CLICK_EVENT_IDENTIFIER) {
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ if ((Event.getEventsSunk(getWidgetForPaintable().splitter) & Event
+ .getTypeInt(type.getName())) != 0) {
+ // If we are already sinking the event for the splitter we do
+ // not want to additionally sink it for the root element
+ return getWidgetForPaintable().addHandler(handler, type);
+ } else {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ }
+
+ @Override
+ public void onContextMenu(
+ com.google.gwt.event.dom.client.ContextMenuEvent event) {
+ Element target = event.getNativeEvent().getEventTarget().cast();
+ if (getWidgetForPaintable().splitter.isOrHasChild(target)) {
+ super.onContextMenu(event);
+ }
+ };
+
+ @Override
+ protected void fireClick(NativeEvent event) {
+ Element target = event.getEventTarget().cast();
+ if (getWidgetForPaintable().splitter.isOrHasChild(target)) {
+ super.fireClick(event);
+ }
+ }
+
+ @Override
+ protected Element getRelativeToElement() {
+ return null;
+ }
+
+ };
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().id = uidl.getId();
+ getWidgetForPaintable().rendering = true;
+
+ getWidgetForPaintable().immediate = uidl.hasAttribute("immediate");
+
+ if (client.updateComponent(this, uidl, true)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+ getWidgetForPaintable().setEnabled(
+ !uidl.getBooleanAttribute("disabled"));
+
+ clickEventHandler.handleEventHandlerRegistration(client);
+ if (uidl.hasAttribute("style")) {
+ getWidgetForPaintable().componentStyleNames = uidl
+ .getStringAttribute("style").split(" ");
+ } else {
+ getWidgetForPaintable().componentStyleNames = new String[0];
+ }
+
+ getWidgetForPaintable().setLocked(uidl.getBooleanAttribute("locked"));
+
+ getWidgetForPaintable().setPositionReversed(
+ uidl.getBooleanAttribute("reversed"));
+
+ getWidgetForPaintable().setStylenames();
+
+ getWidgetForPaintable().position = uidl.getStringAttribute("position");
+ getWidgetForPaintable().setSplitPosition(
+ getWidgetForPaintable().position);
+
+ final VPaintableWidget newFirstChildPaintable = client
+ .getPaintable(uidl.getChildUIDL(0));
+ final VPaintableWidget newSecondChildPaintable = client
+ .getPaintable(uidl.getChildUIDL(1));
+ Widget newFirstChild = newFirstChildPaintable.getWidgetForPaintable();
+ Widget newSecondChild = newSecondChildPaintable.getWidgetForPaintable();
+
+ if (getWidgetForPaintable().firstChild != newFirstChild) {
+ if (getWidgetForPaintable().firstChild != null) {
+ client.unregisterPaintable(VPaintableMap.get(client)
+ .getPaintable(getWidgetForPaintable().firstChild));
+ }
+ getWidgetForPaintable().setFirstWidget(newFirstChild);
+ }
+ if (getWidgetForPaintable().secondChild != newSecondChild) {
+ if (getWidgetForPaintable().secondChild != null) {
+ client.unregisterPaintable(VPaintableMap.get(client)
+ .getPaintable(getWidgetForPaintable().secondChild));
+ }
+ getWidgetForPaintable().setSecondWidget(newSecondChild);
+ }
+ newFirstChildPaintable.updateFromUIDL(uidl.getChildUIDL(0), client);
+ newSecondChildPaintable.updateFromUIDL(uidl.getChildUIDL(1), client);
+
+ getWidgetForPaintable().renderInformation
+ .updateSize(getWidgetForPaintable().getElement());
+
+ // This is needed at least for cases like #3458 to take
+ // appearing/disappearing scrollbars into account.
+ client.runDescendentsLayout(getWidgetForPaintable());
+
+ getWidgetForPaintable().rendering = false;
+
+ }
+
+ @Override
+ public VAbstractSplitPanel getWidgetForPaintable() {
+ return (VAbstractSplitPanel) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected abstract VAbstractSplitPanel createWidget();
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java b/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java
index 4d0776a5f9..3e4f21477b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java
@@ -15,80 +15,40 @@ import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
public class VAccordion extends VTabsheetBase implements
ContainerResizedListener {
public static final String CLASSNAME = "v-accordion";
- private Set<Paintable> paintables = new HashSet<Paintable>();
+ private Set<Widget> widgets = new HashSet<Widget>();
private String height;
private String width = "";
- private HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>();
+ HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>();
private RenderSpace renderSpace = new RenderSpace(0, 0, true);
- private StackItem openTab = null;
+ StackItem openTab = null;
- private boolean rendering = false;
+ boolean rendering = false;
- private int selectedUIDLItemIndex = -1;
+ int selectedUIDLItemIndex = -1;
- private RenderInformation renderInformation = new RenderInformation();
+ RenderInformation renderInformation = new RenderInformation();
public VAccordion() {
super(CLASSNAME);
- // IE6 needs this to calculate offsetHeight correctly
- if (BrowserInfo.get().isIE6()) {
- DOM.setStyleAttribute(getElement(), "zoom", "1");
- }
- }
-
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
- selectedUIDLItemIndex = -1;
- super.updateFromUIDL(uidl, client);
- /*
- * Render content after all tabs have been created and we know how large
- * the content area is
- */
- if (selectedUIDLItemIndex >= 0) {
- StackItem selectedItem = getStackItem(selectedUIDLItemIndex);
- UIDL selectedTabUIDL = lazyUpdateMap.remove(selectedItem);
- open(selectedUIDLItemIndex);
-
- selectedItem.setContent(selectedTabUIDL);
- } else if (!uidl.getBooleanAttribute("cached") && openTab != null) {
- close(openTab);
- }
-
- iLayout();
- // finally render possible hidden tabs
- if (lazyUpdateMap.size() > 0) {
- for (Iterator iterator = lazyUpdateMap.keySet().iterator(); iterator
- .hasNext();) {
- StackItem item = (StackItem) iterator.next();
- item.setContent(lazyUpdateMap.get(item));
- }
- lazyUpdateMap.clear();
- }
-
- renderInformation.updateSize(getElement());
-
- rendering = false;
}
@Override
@@ -137,7 +97,7 @@ public class VAccordion extends VTabsheetBase implements
private StackItem moveStackItemIfNeeded(StackItem item, int newIndex,
UIDL tabUidl) {
UIDL tabContentUIDL = null;
- Paintable tabContent = null;
+ VPaintableWidget tabContent = null;
if (tabUidl.getChildCount() > 0) {
tabContentUIDL = tabUidl.getChildUIDL(0);
tabContent = client.getPaintable(tabContentUIDL);
@@ -186,7 +146,7 @@ public class VAccordion extends VTabsheetBase implements
return item;
}
- private void open(int itemIndex) {
+ void open(int itemIndex) {
StackItem item = (StackItem) getWidget(itemIndex);
boolean alreadyOpen = false;
if (openTab != null) {
@@ -209,7 +169,7 @@ public class VAccordion extends VTabsheetBase implements
updateOpenTabSize();
}
- private void close(StackItem item) {
+ void close(StackItem item) {
if (!item.isOpen()) {
return;
}
@@ -383,12 +343,12 @@ public class VAccordion extends VTabsheetBase implements
}
public void setHeightFromWidget() {
- Widget paintable = getPaintable();
- if (paintable == null) {
+ Widget widget = getChildWidget();
+ if (widget == null) {
return;
}
- int paintableHeight = (paintable).getElement().getOffsetHeight();
+ int paintableHeight = widget.getElement().getOffsetHeight();
setHeight(paintableHeight);
}
@@ -434,10 +394,6 @@ public class VAccordion extends VTabsheetBase implements
setElement(DOM.createDiv());
caption = new VCaption(null, client);
caption.addClickHandler(this);
- if (BrowserInfo.get().isIE6()) {
- DOM.setEventListener(captionNode, this);
- DOM.sinkEvents(captionNode, Event.BUTTON_LEFT);
- }
super.add(caption, captionNode);
DOM.appendChild(captionNode, caption.getElement());
DOM.appendChild(getElement(), captionNode);
@@ -459,7 +415,7 @@ public class VAccordion extends VTabsheetBase implements
return content;
}
- public Widget getPaintable() {
+ public Widget getChildWidget() {
if (getWidgetCount() > 1) {
return getWidget(1);
} else {
@@ -467,14 +423,17 @@ public class VAccordion extends VTabsheetBase implements
}
}
- public void replacePaintable(Paintable newPntbl) {
+ public void replaceWidget(Widget newWidget) {
if (getWidgetCount() > 1) {
- client.unregisterPaintable((Paintable) getWidget(1));
- paintables.remove(getWidget(1));
+ Widget oldWidget = getWidget(1);
+ VPaintableWidget oldPaintable = VPaintableMap.get(client)
+ .getPaintable(oldWidget);
+ VPaintableMap.get(client).unregisterPaintable(oldPaintable);
+ widgets.remove(oldWidget);
remove(1);
}
- add((Widget) newPntbl, content);
- paintables.add(newPntbl);
+ add(newWidget, content);
+ widgets.add(newWidget);
}
public void open() {
@@ -496,10 +455,6 @@ public class VAccordion extends VTabsheetBase implements
removeStyleDependentName("open");
setHeight(-1);
setWidth("");
- if (BrowserInfo.get().isIE6()) {
- // Work around for IE6 layouting problem #3359
- getElement().getStyle().setProperty("zoom", "1");
- }
open = false;
}
@@ -508,12 +463,13 @@ public class VAccordion extends VTabsheetBase implements
}
public void setContent(UIDL contentUidl) {
- final Paintable newPntbl = client.getPaintable(contentUidl);
- if (getPaintable() == null) {
- add((Widget) newPntbl, content);
- paintables.add(newPntbl);
- } else if (getPaintable() != newPntbl) {
- replacePaintable(newPntbl);
+ final VPaintableWidget newPntbl = client.getPaintable(contentUidl);
+ Widget newWidget = newPntbl.getWidgetForPaintable();
+ if (getChildWidget() == null) {
+ add(newWidget, content);
+ widgets.add(newWidget);
+ } else if (getChildWidget() != newWidget) {
+ replaceWidget(newWidget);
}
newPntbl.updateFromUIDL(contentUidl, client);
if (contentUidl.getBooleanAttribute("cached")) {
@@ -521,7 +477,8 @@ public class VAccordion extends VTabsheetBase implements
* The size of a cached, relative sized component must be
* updated to report correct size.
*/
- client.handleComponentRelativeSize((Widget) newPntbl);
+ client.handleComponentRelativeSize(newPntbl
+ .getWidgetForPaintable());
}
if (isOpen() && isDynamicHeight()) {
setHeightFromWidget();
@@ -540,8 +497,8 @@ public class VAccordion extends VTabsheetBase implements
return DOM.getFirstChild(content).getOffsetWidth();
}
- public boolean contains(Paintable p) {
- return (getPaintable() == p);
+ public boolean contains(VPaintableWidget p) {
+ return (getChildWidget() == p.getWidgetForPaintable());
}
public boolean isCaptionVisible() {
@@ -565,41 +522,38 @@ public class VAccordion extends VTabsheetBase implements
@Override
@SuppressWarnings("unchecked")
- protected Iterator<Object> getPaintableIterator() {
- return (Iterator) paintables.iterator();
+ protected Iterator<Widget> getWidgetIterator() {
+ return widgets.iterator();
}
public boolean hasChildComponent(Widget component) {
- if (paintables.contains(component)) {
- return true;
- } else {
- return false;
+ for (Widget w : widgets) {
+ if (w == component) {
+ return true;
+ }
}
+ return false;
}
public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
for (Widget w : getChildren()) {
StackItem item = (StackItem) w;
- if (item.getPaintable() == oldComponent) {
- item.replacePaintable((Paintable) newComponent);
+ if (item.getChildWidget() == oldComponent) {
+ item.replaceWidget(newComponent);
return;
}
}
}
- public void updateCaption(Paintable component, UIDL uidl) {
- /* Accordion does not render its children's captions */
- }
-
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
if (!isDynamicHeight() && !isDynamicWidth()) {
/*
* If the height and width has been specified for this container the
* child components cannot make the size of the layout change
*/
// layout size change may affect its available space (scrollbars)
- for (Paintable paintable : child) {
- client.handleComponentRelativeSize((Widget) paintable);
+ for (Widget widget : children) {
+ client.handleComponentRelativeSize(widget);
}
return true;
@@ -643,15 +597,17 @@ public class VAccordion extends VTabsheetBase implements
}
@Override
- protected Paintable getTab(int index) {
+ protected VPaintableWidget getTab(int index) {
if (index < getWidgetCount()) {
- return (Paintable) (getStackItem(index)).getPaintable();
+ Widget w = getStackItem(index);
+ return VPaintableMap.get(client).getPaintable(w);
}
return null;
}
- private StackItem getStackItem(int index) {
+ StackItem getStackItem(int index) {
return (StackItem) getWidget(index);
}
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAccordionPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VAccordionPaintable.java
new file mode 100644
index 0000000000..4136d02c30
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAccordionPaintable.java
@@ -0,0 +1,68 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.VAccordion.StackItem;
+
+public class VAccordionPaintable extends VTabsheetBasePaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+ getWidgetForPaintable().selectedUIDLItemIndex = -1;
+ super.updateFromUIDL(uidl, client);
+ /*
+ * Render content after all tabs have been created and we know how large
+ * the content area is
+ */
+ if (getWidgetForPaintable().selectedUIDLItemIndex >= 0) {
+ StackItem selectedItem = getWidgetForPaintable().getStackItem(
+ getWidgetForPaintable().selectedUIDLItemIndex);
+ UIDL selectedTabUIDL = getWidgetForPaintable().lazyUpdateMap
+ .remove(selectedItem);
+ getWidgetForPaintable().open(
+ getWidgetForPaintable().selectedUIDLItemIndex);
+
+ selectedItem.setContent(selectedTabUIDL);
+ } else if (!uidl.getBooleanAttribute("cached")
+ && getWidgetForPaintable().openTab != null) {
+ getWidgetForPaintable().close(getWidgetForPaintable().openTab);
+ }
+
+ getWidgetForPaintable().iLayout();
+ // finally render possible hidden tabs
+ if (getWidgetForPaintable().lazyUpdateMap.size() > 0) {
+ for (Iterator iterator = getWidgetForPaintable().lazyUpdateMap
+ .keySet().iterator(); iterator.hasNext();) {
+ StackItem item = (StackItem) iterator.next();
+ item.setContent(getWidgetForPaintable().lazyUpdateMap.get(item));
+ }
+ getWidgetForPaintable().lazyUpdateMap.clear();
+ }
+
+ getWidgetForPaintable().renderInformation
+ .updateSize(getWidgetForPaintable().getElement());
+
+ getWidgetForPaintable().rendering = false;
+ }
+
+ @Override
+ public VAccordion getWidgetForPaintable() {
+ return (VAccordion) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VAccordion.class);
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ /* Accordion does not render its children's captions */
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAudio.java b/src/com/vaadin/terminal/gwt/client/ui/VAudio.java
index 1fdfaca831..f6df827237 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VAudio.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAudio.java
@@ -6,11 +6,6 @@ package com.vaadin.terminal.gwt.client.ui;
import com.google.gwt.dom.client.AudioElement;
import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.Unit;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.UIDL;
public class VAudio extends VMediaBase {
private static String CLASSNAME = "v-audio";
@@ -24,26 +19,8 @@ public class VAudio extends VMediaBase {
}
@Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
- super.updateFromUIDL(uidl, client);
- Style style = audio.getStyle();
-
- // Make sure that the controls are not clipped if visible.
- if (shouldShowControls(uidl)
- && (style.getHeight() == null || "".equals(style.getHeight()))) {
- if (BrowserInfo.get().isChrome()) {
- style.setHeight(32, Unit.PX);
- } else {
- style.setHeight(25, Unit.PX);
- }
- }
- }
-
- @Override
protected String getDefaultAltHtml() {
return "Your browser does not support the <code>audio</code> element.";
}
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAudioPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VAudioPaintable.java
new file mode 100644
index 0000000000..dae602a668
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAudioPaintable.java
@@ -0,0 +1,37 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VAudioPaintable extends VMediaBasePaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+ super.updateFromUIDL(uidl, client);
+ Style style = getWidgetForPaintable().getElement().getStyle();
+
+ // Make sure that the controls are not clipped if visible.
+ if (shouldShowControls(uidl)
+ && (style.getHeight() == null || "".equals(style.getHeight()))) {
+ if (BrowserInfo.get().isChrome()) {
+ style.setHeight(32, Unit.PX);
+ } else {
+ style.setHeight(25, Unit.PX);
+ }
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VAudio.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/VButton.java
index 03de99ada6..21b5d8bbe8 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VButton.java
@@ -21,16 +21,13 @@ import com.google.gwt.user.client.ui.Accessibility;
import com.google.gwt.user.client.ui.FocusWidget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.EventHelper;
import com.vaadin.terminal.gwt.client.EventId;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VButton extends FocusWidget implements Paintable, ClickHandler,
- FocusHandler, BlurHandler {
+public class VButton extends FocusWidget implements ClickHandler, FocusHandler,
+ BlurHandler {
public static final String CLASSNAME = "v-button";
private static final String CLASSNAME_PRESSED = "v-pressed";
@@ -42,7 +39,7 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
protected int mousedownX = 0;
protected int mousedownY = 0;
- protected String id;
+ protected String paintableId;
protected ApplicationConnection client;
@@ -65,7 +62,7 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
private int tabIndex = 0;
- private boolean disableOnClick = false;
+ protected boolean disableOnClick = false;
/*
* BELOW PRIVATE MEMBERS COPY-PASTED FROM GWT CustomButton
@@ -88,10 +85,10 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
private boolean disallowNextClick = false;
private boolean isHovering;
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
+ protected HandlerRegistration focusHandlerRegistration;
+ protected HandlerRegistration blurHandlerRegistration;
- private int clickShortcut = 0;
+ protected int clickShortcut = 0;
public VButton() {
super(DOM.createDiv());
@@ -113,64 +110,6 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
addClickHandler(this);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
- // Ensure correct implementation,
- // but don't let container manage caption etc.
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
-
- focusHandlerRegistration = EventHelper.updateFocusHandler(this, client,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this, client,
- blurHandlerRegistration);
-
- // Save details
- this.client = client;
- id = uidl.getId();
-
- // Set text
- setText(uidl.getStringAttribute("caption"));
-
- disableOnClick = uidl.hasAttribute(ATTR_DISABLE_ON_CLICK);
-
- // handle error
- if (uidl.hasAttribute("error")) {
- if (errorIndicatorElement == null) {
- errorIndicatorElement = DOM.createSpan();
- errorIndicatorElement.setClassName("v-errorindicator");
- }
- wrapper.insertBefore(errorIndicatorElement, captionElement);
-
- // Fix for IE6, IE7
- if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) {
- errorIndicatorElement.setInnerText(" ");
- }
-
- } else if (errorIndicatorElement != null) {
- wrapper.removeChild(errorIndicatorElement);
- errorIndicatorElement = null;
- }
-
- if (uidl.hasAttribute("icon")) {
- if (icon == null) {
- icon = new Icon(client);
- wrapper.insertBefore(icon.getElement(), captionElement);
- }
- icon.setUri(uidl.getStringAttribute("icon"));
- } else {
- if (icon != null) {
- wrapper.removeChild(icon.getElement());
- icon = null;
- }
- }
-
- if (uidl.hasAttribute("keycode")) {
- clickShortcut = uidl.getIntAttribute("keycode");
- }
- }
-
public void setText(String text) {
captionElement.setInnerText(text);
}
@@ -191,7 +130,7 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
*/
public void onBrowserEvent(Event event) {
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
if (DOM.eventGetType(event) == Event.ONLOAD) {
Util.notifyParentOfSizeChange(this, true);
@@ -353,7 +292,7 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
* .dom.client.ClickEvent)
*/
public void onClick(ClickEvent event) {
- if (id == null || client == null) {
+ if (paintableId == null || client == null) {
return;
}
if (BrowserInfo.get().isSafari()) {
@@ -361,15 +300,16 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
}
if (disableOnClick) {
setEnabled(false);
- client.updateVariable(id, "disabledOnClick", true, false);
+ client.updateVariable(paintableId, "disabledOnClick", true, false);
}
- client.updateVariable(id, "state", true, false);
+ client.updateVariable(paintableId, "state", true, false);
// Add mouse details
MouseEventDetails details = new MouseEventDetails(
event.getNativeEvent(), getElement());
- client.updateVariable(id, "mousedetails", details.serialize(), true);
+ client.updateVariable(paintableId, "mousedetails", details.serialize(),
+ true);
clickPending = false;
}
@@ -451,25 +391,6 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
}
}
- @Override
- public void setWidth(String width) {
- if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) {
- if (width != null && width.length() > 2) {
- // Assume pixel values are always sent from
- // ApplicationConnection
- int w = Integer
- .parseInt(width.substring(0, width.length() - 2));
- w -= getHorizontalBorderAndPaddingWidth(getElement());
- if (w < 0) {
- // validity check for IE
- w = 0;
- }
- width = w + "px";
- }
- }
- super.setWidth(width);
- }
-
private static native int getHorizontalBorderAndPaddingWidth(Element elem)
/*-{
// THIS METHOD IS ONLY USED FOR INTERNET EXPLORER, IT DOESN'T WORK WITH OTHERS
@@ -522,11 +443,10 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler,
}-*/;
public void onFocus(FocusEvent arg0) {
- client.updateVariable(id, EventId.FOCUS, "", true);
+ client.updateVariable(paintableId, EventId.FOCUS, "", true);
}
public void onBlur(BlurEvent arg0) {
- client.updateVariable(id, EventId.BLUR, "", true);
+ client.updateVariable(paintableId, EventId.BLUR, "", true);
}
-
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VButtonPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VButtonPaintable.java
new file mode 100644
index 0000000000..98f2888700
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VButtonPaintable.java
@@ -0,0 +1,91 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.EventHelper;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VButtonPaintable extends VAbstractPaintableWidget {
+
+ 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;
+ }
+
+ getWidgetForPaintable().focusHandlerRegistration = EventHelper
+ .updateFocusHandler(this, client,
+ getWidgetForPaintable().focusHandlerRegistration);
+ getWidgetForPaintable().blurHandlerRegistration = EventHelper
+ .updateBlurHandler(this, client,
+ getWidgetForPaintable().blurHandlerRegistration);
+
+ // Save details
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getId();
+
+ // Set text
+ getWidgetForPaintable().setText(uidl.getStringAttribute("caption"));
+
+ getWidgetForPaintable().disableOnClick = uidl
+ .hasAttribute(VButton.ATTR_DISABLE_ON_CLICK);
+
+ // handle error
+ if (uidl.hasAttribute("error")) {
+ if (getWidgetForPaintable().errorIndicatorElement == null) {
+ getWidgetForPaintable().errorIndicatorElement = DOM
+ .createSpan();
+ getWidgetForPaintable().errorIndicatorElement
+ .setClassName("v-errorindicator");
+ }
+ getWidgetForPaintable().wrapper.insertBefore(
+ getWidgetForPaintable().errorIndicatorElement,
+ getWidgetForPaintable().captionElement);
+
+ } else if (getWidgetForPaintable().errorIndicatorElement != null) {
+ getWidgetForPaintable().wrapper
+ .removeChild(getWidgetForPaintable().errorIndicatorElement);
+ getWidgetForPaintable().errorIndicatorElement = null;
+ }
+
+ if (uidl.hasAttribute("icon")) {
+ if (getWidgetForPaintable().icon == null) {
+ getWidgetForPaintable().icon = new Icon(client);
+ getWidgetForPaintable().wrapper.insertBefore(
+ getWidgetForPaintable().icon.getElement(),
+ getWidgetForPaintable().captionElement);
+ }
+ getWidgetForPaintable().icon
+ .setUri(uidl.getStringAttribute("icon"));
+ } else {
+ if (getWidgetForPaintable().icon != null) {
+ getWidgetForPaintable().wrapper
+ .removeChild(getWidgetForPaintable().icon.getElement());
+ getWidgetForPaintable().icon = null;
+ }
+ }
+
+ if (uidl.hasAttribute("keycode")) {
+ getWidgetForPaintable().clickShortcut = uidl
+ .getIntAttribute("keycode");
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VButton.class);
+ }
+
+ @Override
+ public VButton getWidgetForPaintable() {
+ return (VButton) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java
index a2f03d6176..b5c07ca278 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java
@@ -40,6 +40,7 @@ import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.DateTimeService;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.ui.label.VLabel;
@SuppressWarnings("deprecation")
public class VCalendarPanel extends FocusableFlexTable implements
@@ -1142,7 +1143,7 @@ public class VCalendarPanel extends FocusableFlexTable implements
// elapsed, another timer is triggered to go off every 150ms. Both
// timers are cancelled on mouseup or mouseout.
if (event.getSource() instanceof VEventButton) {
- final Widget sender = (Widget) event.getSource();
+ final VEventButton sender = (VEventButton) event.getSource();
processClickEvent(sender);
mouseTimer = new Timer() {
@Override
@@ -1225,8 +1226,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
private ListBox sec;
- private ListBox msec;
-
private ListBox ampm;
/**
@@ -1291,19 +1290,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
sec.addChangeHandler(this);
}
- if (getResolution() == VDateField.RESOLUTION_MSEC) {
- msec = createListBox();
- for (int i = 0; i < 1000; i++) {
- if (i < 10) {
- msec.addItem("00" + i);
- } else if (i < 100) {
- msec.addItem("0" + i);
- } else {
- msec.addItem("" + i);
- }
- }
- msec.addChangeHandler(this);
- }
final String delimiter = getDateTimeService().getClockDelimeter();
if (isReadonly()) {
@@ -1337,16 +1323,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
add(sec);
}
}
- if (getResolution() == VDateField.RESOLUTION_MSEC) {
- add(new VLabel("."));
- if (isReadonly()) {
- final int m = getMilliseconds();
- final String ms = m < 100 ? "0" + m : "" + m;
- add(new VLabel(m < 10 ? "0" + ms : ms));
- } else {
- add(msec);
- }
- }
if (getResolution() == VDateField.RESOLUTION_HOUR) {
add(new VLabel(delimiter + "00")); // o'clock
}
@@ -1422,13 +1398,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (getResolution() >= VDateField.RESOLUTION_SEC) {
sec.setSelectedIndex(value.getSeconds());
}
- if (getResolution() == VDateField.RESOLUTION_MSEC) {
- if (selected) {
- msec.setSelectedIndex(getMilliseconds());
- } else {
- msec.setSelectedIndex(0);
- }
- }
if (getDateTimeService().isTwelveHourClock()) {
ampm.setSelectedIndex(value.getHours() < 12 ? 0 : 1);
}
@@ -1440,9 +1409,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (sec != null) {
sec.setEnabled(isEnabled());
}
- if (msec != null) {
- msec.setEnabled(isEnabled());
- }
if (ampm != null) {
ampm.setEnabled(isEnabled());
}
@@ -1505,15 +1471,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
event.preventDefault();
event.stopPropagation();
- } else if (event.getSource() == msec) {
- final int ms = msec.getSelectedIndex();
- DateTimeService.setMilliseconds(value, ms);
- if (timeChangeListener != null) {
- timeChangeListener.changed(value.getHours(),
- value.getMinutes(), value.getSeconds(), ms);
- }
- event.preventDefault();
- event.stopPropagation();
} else if (event.getSource() == ampm) {
final int h = hours.getSelectedIndex()
+ (ampm.getSelectedIndex() * 12);
@@ -1696,8 +1653,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
return SUBPART_MINUTE_SELECT;
} else if (contains(time.sec, subElement)) {
return SUBPART_SECS_SELECT;
- } else if (contains(time.msec, subElement)) {
- return SUBPART_MSECS_SELECT;
} else if (contains(time.ampm, subElement)) {
return SUBPART_AMPM_SELECT;
@@ -1746,9 +1701,6 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (SUBPART_SECS_SELECT.equals(subPart)) {
return time.sec.getElement();
}
- if (SUBPART_MSECS_SELECT.equals(subPart)) {
- return time.msec.getElement();
- }
if (SUBPART_AMPM_SELECT.equals(subPart)) {
return time.ampm.getElement();
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java b/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java
index c43c4d3dba..d92d7e37ed 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java
@@ -4,10 +4,6 @@
package com.vaadin.terminal.gwt.client.ui;
-import com.google.gwt.dom.client.InputElement;
-import com.google.gwt.dom.client.LabelElement;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -18,18 +14,17 @@ import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.EventHelper;
import com.vaadin.terminal.gwt.client.EventId;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
- Paintable, Field, FocusHandler, BlurHandler {
+ Field, FocusHandler, BlurHandler {
+
+ public static final String VARIABLE_STATE = "state";
public static final String CLASSNAME = "v-checkbox";
@@ -39,12 +34,12 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
ApplicationConnection client;
- private Element errorIndicatorElement;
+ Element errorIndicatorElement;
- private Icon icon;
+ Icon icon;
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
+ HandlerRegistration focusHandlerRegistration;
+ HandlerRegistration blurHandlerRegistration;
public VCheckBox() {
setStyleName(CLASSNAME);
@@ -60,7 +55,7 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
event.getNativeEvent(), getElement());
client.updateVariable(id, "mousedetails", details.serialize(),
false);
- client.updateVariable(id, "state", getValue(), immediate);
+ client.updateVariable(id, VARIABLE_STATE, getValue(), immediate);
}
});
@@ -73,91 +68,6 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
}
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // Save details
- this.client = client;
- id = uidl.getId();
-
- // Ensure correct implementation
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
-
- focusHandlerRegistration = EventHelper.updateFocusHandler(this, client,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this, client,
- blurHandlerRegistration);
-
- if (uidl.hasAttribute("error")) {
- if (errorIndicatorElement == null) {
- errorIndicatorElement = DOM.createSpan();
- errorIndicatorElement.setInnerHTML("&nbsp;");
- DOM.setElementProperty(errorIndicatorElement, "className",
- "v-errorindicator");
- DOM.appendChild(getElement(), errorIndicatorElement);
- DOM.sinkEvents(errorIndicatorElement, VTooltip.TOOLTIP_EVENTS
- | Event.ONCLICK);
- } else {
- DOM.setStyleAttribute(errorIndicatorElement, "display", "");
- }
- } else if (errorIndicatorElement != null) {
- DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
- }
-
- if (uidl.hasAttribute("readonly")) {
- setEnabled(false);
- }
-
- if (uidl.hasAttribute("icon")) {
- if (icon == null) {
- icon = new Icon(client);
- DOM.insertChild(getElement(), icon.getElement(), 1);
- icon.sinkEvents(VTooltip.TOOLTIP_EVENTS);
- icon.sinkEvents(Event.ONCLICK);
- }
- icon.setUri(uidl.getStringAttribute("icon"));
- } else if (icon != null) {
- // detach icon
- DOM.removeChild(getElement(), icon.getElement());
- icon = null;
- }
-
- // Set text
- setText(uidl.getStringAttribute("caption"));
- setValue(uidl.getBooleanVariable("state"));
- immediate = uidl.getBooleanAttribute("immediate");
- }
-
- @Override
- public void setText(String text) {
- super.setText(text);
- if (BrowserInfo.get().isIE() && BrowserInfo.get().getIEVersion() < 8) {
-
- boolean breakLink = text == null || "".equals(text);
-
- // break or create link between label element and checkbox, to
- // enable native focus outline around checkbox element itself, if
- // caption is not present
- NodeList<Node> childNodes = getElement().getChildNodes();
- String id = null;
- for (int i = 0; i < childNodes.getLength(); i++) {
- Node item = childNodes.getItem(i);
- if (item.getNodeName().toLowerCase().equals("input")) {
- InputElement input = (InputElement) item;
- id = input.getId();
- }
- if (item.getNodeName().toLowerCase().equals("label")) {
- LabelElement label = (LabelElement) item;
- if (breakLink) {
- label.setHtmlFor("");
- } else {
- label.setHtmlFor(id);
- }
- }
- }
- }
- }
-
@Override
public void onBrowserEvent(Event event) {
if (icon != null && (event.getTypeInt() == Event.ONCLICK)
@@ -169,7 +79,7 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
Util.notifyParentOfSizeChange(this, true);
}
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
}
@@ -190,4 +100,9 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
public void onBlur(BlurEvent arg0) {
client.updateVariable(id, EventId.BLUR, "", true);
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCheckBoxPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VCheckBoxPaintable.java
new file mode 100644
index 0000000000..06ef54c13a
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCheckBoxPaintable.java
@@ -0,0 +1,96 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.EventHelper;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VTooltip;
+
+public class VCheckBoxPaintable extends VAbstractPaintableWidget {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Save details
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().id = uidl.getId();
+
+ // Ensure correct implementation
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+
+ getWidgetForPaintable().focusHandlerRegistration = EventHelper
+ .updateFocusHandler(this, client,
+ getWidgetForPaintable().focusHandlerRegistration);
+ getWidgetForPaintable().blurHandlerRegistration = EventHelper
+ .updateBlurHandler(this, client,
+ getWidgetForPaintable().blurHandlerRegistration);
+
+ if (uidl.hasAttribute("error")) {
+ if (getWidgetForPaintable().errorIndicatorElement == null) {
+ getWidgetForPaintable().errorIndicatorElement = DOM
+ .createSpan();
+ getWidgetForPaintable().errorIndicatorElement
+ .setInnerHTML("&nbsp;");
+ DOM.setElementProperty(
+ getWidgetForPaintable().errorIndicatorElement,
+ "className", "v-errorindicator");
+ DOM.appendChild(getWidgetForPaintable().getElement(),
+ getWidgetForPaintable().errorIndicatorElement);
+ DOM.sinkEvents(getWidgetForPaintable().errorIndicatorElement,
+ VTooltip.TOOLTIP_EVENTS | Event.ONCLICK);
+ } else {
+ DOM.setStyleAttribute(
+ getWidgetForPaintable().errorIndicatorElement,
+ "display", "");
+ }
+ } else if (getWidgetForPaintable().errorIndicatorElement != null) {
+ DOM.setStyleAttribute(
+ getWidgetForPaintable().errorIndicatorElement, "display",
+ "none");
+ }
+
+ if (uidl.hasAttribute("readonly")) {
+ getWidgetForPaintable().setEnabled(false);
+ }
+
+ if (uidl.hasAttribute("icon")) {
+ if (getWidgetForPaintable().icon == null) {
+ getWidgetForPaintable().icon = new Icon(client);
+ DOM.insertChild(getWidgetForPaintable().getElement(),
+ getWidgetForPaintable().icon.getElement(), 1);
+ getWidgetForPaintable().icon
+ .sinkEvents(VTooltip.TOOLTIP_EVENTS);
+ getWidgetForPaintable().icon.sinkEvents(Event.ONCLICK);
+ }
+ getWidgetForPaintable().icon
+ .setUri(uidl.getStringAttribute("icon"));
+ } else if (getWidgetForPaintable().icon != null) {
+ // detach icon
+ DOM.removeChild(getWidgetForPaintable().getElement(),
+ getWidgetForPaintable().icon.getElement());
+ getWidgetForPaintable().icon = null;
+ }
+
+ // Set text
+ getWidgetForPaintable().setText(uidl.getStringAttribute("caption"));
+ getWidgetForPaintable()
+ .setValue(
+ uidl.getBooleanVariable(getWidgetForPaintable().VARIABLE_STATE));
+ getWidgetForPaintable().immediate = uidl
+ .getBooleanAttribute("immediate");
+ }
+
+ @Override
+ public VCheckBox getWidgetForPaintable() {
+ return (VCheckBox) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VCheckBox.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java b/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java
index 8158fd90c2..e46a74346b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java
@@ -31,7 +31,6 @@ import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.impl.FocusImpl;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Focusable;
import com.vaadin.terminal.gwt.client.Util;
@@ -218,11 +217,6 @@ public class VContextMenu extends VOverlay implements SubPartAware {
public void onLoad(LoadEvent event) {
// Handle icon onload events to ensure shadow is resized correctly
- if (BrowserInfo.get().isIE6()) {
- // Ensure PNG transparency works in IE6
- Util.doIE6PngFix((Element) Element.as(event.getNativeEvent()
- .getEventTarget()));
- }
delayedImageLoadExecutioner.trigger();
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java
index 585180f8f4..e56d333dad 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java
@@ -11,9 +11,6 @@ import java.util.Iterator;
import java.util.Set;
import com.google.gwt.dom.client.Style;
-import com.google.gwt.event.dom.client.DomEvent.Type;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -22,42 +19,27 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.StyleConstants;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ValueMap;
-public class VCssLayout extends SimplePanel implements Paintable, Container {
+public class VCssLayout extends SimplePanel implements Container {
public static final String TAGNAME = "csslayout";
public static final String CLASSNAME = "v-" + TAGNAME;
- private FlowPane panel = new FlowPane();
+ FlowPane panel = new FlowPane();
- private Element margin = DOM.createDiv();
-
- private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
- this, EventId.LAYOUT_CLICK) {
-
- @Override
- protected Paintable getChildComponent(Element element) {
- return panel.getComponent(element);
- }
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
- };
+ Element margin = DOM.createDiv();
private boolean hasHeight;
private boolean hasWidth;
- private boolean rendering;
+ boolean rendering;
public VCssLayout() {
super();
@@ -92,32 +74,6 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
}
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
-
- if (client.updateComponent(this, uidl, true)) {
- rendering = false;
- return;
- }
- clickEventHandler.handleEventHandlerRegistration(client);
-
- final VMarginInfo margins = new VMarginInfo(
- uidl.getIntAttribute("margins"));
- setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP,
- margins.hasTop());
- setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT,
- margins.hasRight());
- setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM,
- margins.hasBottom());
- setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT,
- margins.hasLeft());
-
- setStyleName(margin, CLASSNAME + "-" + "spacing",
- uidl.hasAttribute("spacing"));
- panel.updateFromUIDL(uidl, client);
- rendering = false;
- }
-
public boolean hasChildComponent(Widget component) {
return panel.hasChildComponent(component);
}
@@ -126,10 +82,6 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
panel.replaceChildComponent(oldComponent, newComponent);
}
- public void updateCaption(Paintable component, UIDL uidl) {
- panel.updateCaption(component, uidl);
- }
-
public class FlowPane extends FlowPanel {
private final HashMap<Widget, VCaption> widgetToCaption = new HashMap<Widget, VCaption>();
@@ -143,7 +95,7 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
public void updateRelativeSizes() {
for (Widget w : getChildren()) {
- if (w instanceof Paintable) {
+ if (w instanceof VPaintableWidget) {
client.handleComponentRelativeSize(w);
}
}
@@ -169,11 +121,11 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
for (final Iterator<Object> i = uidl.getChildIterator(); i
.hasNext();) {
final UIDL r = (UIDL) i.next();
- final Paintable child = client.getPaintable(r);
- final Widget widget = (Widget) child;
+ final VPaintableWidget child = client.getPaintable(r);
+ final Widget widget = child.getWidgetForPaintable();
if (widget.getParent() == this) {
- oldWidgets.remove(child);
- VCaption vCaption = widgetToCaption.get(child);
+ oldWidgets.remove(widget);
+ VCaption vCaption = widgetToCaption.get(widget);
if (vCaption != null) {
addOrMove(vCaption, lastIndex++);
oldWidgets.remove(vCaption);
@@ -212,8 +164,10 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
// them
for (Widget w : oldWidgets) {
remove(w);
- if (w instanceof Paintable) {
- final Paintable p = (Paintable) w;
+ VPaintableMap paintableMap = VPaintableMap.get(client);
+ if (paintableMap.isPaintable(w)) {
+ final VPaintableWidget p = VPaintableMap.get(client)
+ .getPaintable(w);
client.unregisterPaintable(p);
}
VCaption vCaption = widgetToCaption.remove(w);
@@ -251,12 +205,12 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
}
}
- public void updateCaption(Paintable component, UIDL uidl) {
- VCaption caption = widgetToCaption.get(component);
+ public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
+ Widget widget = paintable.getWidgetForPaintable();
+ VCaption caption = widgetToCaption.get(widget);
if (VCaption.isNeeded(uidl)) {
- Widget widget = (Widget) component;
if (caption == null) {
- caption = new VCaption(component, client);
+ caption = new VCaption(paintable, client);
widgetToCaption.put(widget, caption);
insert(caption, getWidgetIndex(widget));
lastIndex++;
@@ -267,11 +221,11 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
caption.updateCaption(uidl);
} else if (caption != null) {
remove(caption);
- widgetToCaption.remove(component);
+ widgetToCaption.remove(widget);
}
}
- private Paintable getComponent(Element element) {
+ VPaintableWidget getComponent(Element element) {
return Util
.getPaintableForElement(client, VCssLayout.this, element);
}
@@ -307,7 +261,7 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
return space;
}
- public boolean requestLayout(Set<Paintable> children) {
+ public boolean requestLayout(Set<Widget> children) {
if (hasSize()) {
return true;
} else {
@@ -339,4 +293,32 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
}
return cssProperty;
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
+ /**
+ * Sets CSS classes for margin and spacing based on the given parameters.
+ *
+ * @param margins
+ * A {@link VMarginInfo} object that provides info on
+ * top/left/bottom/right margins
+ * @param spacing
+ * true to enable spacing, false otherwise
+ */
+ protected void setMarginAndSpacingStyles(VMarginInfo margins,
+ boolean spacing) {
+ setStyleName(margin, VCssLayout.CLASSNAME + "-"
+ + StyleConstants.MARGIN_TOP, margins.hasTop());
+ setStyleName(margin, VCssLayout.CLASSNAME + "-"
+ + StyleConstants.MARGIN_RIGHT, margins.hasRight());
+ setStyleName(margin, VCssLayout.CLASSNAME + "-"
+ + StyleConstants.MARGIN_BOTTOM, margins.hasBottom());
+ setStyleName(margin, VCssLayout.CLASSNAME + "-"
+ + StyleConstants.MARGIN_LEFT, margins.hasLeft());
+
+ setStyleName(margin, VCssLayout.CLASSNAME + "-" + "spacing", spacing);
+
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCssLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VCssLayoutPaintable.java
new file mode 100644
index 0000000000..1b4db40962
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCssLayoutPaintable.java
@@ -0,0 +1,61 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.EventId;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VCssLayoutPaintable extends VAbstractPaintableWidgetContainer {
+
+ private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
+ this, EventId.LAYOUT_CLICK) {
+
+ @Override
+ protected VPaintableWidget getChildComponent(Element element) {
+ return getWidgetForPaintable().panel.getComponent(element);
+ }
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ };
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+
+ if (client.updateComponent(this, uidl, true)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ getWidgetForPaintable().setMarginAndSpacingStyles(
+ new VMarginInfo(uidl.getIntAttribute("margins")),
+ uidl.hasAttribute("spacing"));
+ getWidgetForPaintable().panel.updateFromUIDL(uidl, client);
+ getWidgetForPaintable().rendering = false;
+ }
+
+ @Override
+ public VCssLayout getWidgetForPaintable() {
+ return (VCssLayout) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VCssLayout.class);
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ getWidgetForPaintable().panel.updateCaption(component, uidl);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java
index 1fb3f297ad..ca18104c86 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java
@@ -6,78 +6,28 @@ package com.vaadin.terminal.gwt.client.ui;
import java.util.Set;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
public class VCustomComponent extends SimplePanel implements Container {
private static final String CLASSNAME = "v-customcomponent";
private String height;
- private ApplicationConnection client;
- private boolean rendering;
+ ApplicationConnection client;
+ boolean rendering;
private String width;
- private RenderSpace renderSpace = new RenderSpace();
+ RenderSpace renderSpace = new RenderSpace();
public VCustomComponent() {
super();
setStyleName(CLASSNAME);
}
- public void updateFromUIDL(UIDL uidl, final ApplicationConnection client) {
- rendering = true;
- if (client.updateComponent(this, uidl, true)) {
- rendering = false;
- return;
- }
- this.client = client;
-
- final UIDL child = uidl.getChildUIDL(0);
- if (child != null) {
- final Paintable p = client.getPaintable(child);
- if (p != getWidget()) {
- if (getWidget() != null) {
- client.unregisterPaintable((Paintable) getWidget());
- clear();
- }
- setWidget((Widget) p);
- }
- p.updateFromUIDL(child, client);
- }
-
- boolean updateDynamicSize = updateDynamicSize();
- if (updateDynamicSize) {
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- // FIXME deferred relative size update needed to fix some
- // scrollbar issues in sampler. This must be the wrong way
- // to do it. Might be that some other component is broken.
- client.handleComponentRelativeSize(VCustomComponent.this);
-
- }
- });
- }
-
- renderSpace.setWidth(getElement().getOffsetWidth());
- renderSpace.setHeight(getElement().getOffsetHeight());
-
- /*
- * Needed to update client size if the size of this component has
- * changed and the child uses relative size(s).
- */
- client.runDescendentsLayout(this);
-
- rendering = false;
- }
-
- private boolean updateDynamicSize() {
+ boolean updateDynamicSize() {
boolean updated = false;
if (isDynamicWidth()) {
int childWidth = Util.getRequiredWidth(getWidget());
@@ -118,11 +68,7 @@ public class VCustomComponent extends SimplePanel implements Container {
}
}
- public void updateCaption(Paintable component, UIDL uidl) {
- // NOP, custom component dont render composition roots caption
- }
-
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
// If a child grows in size, it will not necessarily be calculated
// correctly unless we remove previous size definitions
if (isDynamicWidth()) {
@@ -165,4 +111,8 @@ public class VCustomComponent extends SimplePanel implements Container {
}
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponentPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponentPaintable.java
new file mode 100644
index 0000000000..7c0568e28e
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponentPaintable.java
@@ -0,0 +1,79 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VCustomComponentPaintable extends
+ VAbstractPaintableWidgetContainer {
+
+ public void updateFromUIDL(UIDL uidl, final ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+ if (client.updateComponent(this, uidl, true)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+ getWidgetForPaintable().client = client;
+
+ final UIDL child = uidl.getChildUIDL(0);
+ if (child != null) {
+ final VPaintableWidget paintable = client.getPaintable(child);
+ Widget widget = paintable.getWidgetForPaintable();
+ if (widget != getWidgetForPaintable().getWidget()) {
+ if (getWidgetForPaintable().getWidget() != null) {
+ client.unregisterPaintable(VPaintableMap.get(client)
+ .getPaintable(getWidgetForPaintable().getWidget()));
+ getWidgetForPaintable().clear();
+ }
+ getWidgetForPaintable().setWidget(widget);
+ }
+ paintable.updateFromUIDL(child, client);
+ }
+
+ boolean updateDynamicSize = getWidgetForPaintable().updateDynamicSize();
+ if (updateDynamicSize) {
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ // FIXME deferred relative size update needed to fix some
+ // scrollbar issues in sampler. This must be the wrong way
+ // to do it. Might be that some other component is broken.
+ client.handleComponentRelativeSize(getWidgetForPaintable());
+
+ }
+ });
+ }
+
+ getWidgetForPaintable().renderSpace.setWidth(getWidgetForPaintable()
+ .getElement().getOffsetWidth());
+ getWidgetForPaintable().renderSpace.setHeight(getWidgetForPaintable()
+ .getElement().getOffsetHeight());
+
+ /*
+ * Needed to update client size if the size of this component has
+ * changed and the child uses relative size(s).
+ */
+ client.runDescendentsLayout(getWidgetForPaintable());
+
+ getWidgetForPaintable().rendering = false;
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VCustomComponent.class);
+ }
+
+ @Override
+ public VCustomComponent getWidgetForPaintable() {
+ return (VCustomComponent) super.getWidgetForPaintable();
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ // NOP, custom component dont render composition roots caption
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java
index 2a40cd0fe3..7a5f630587 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java
@@ -20,13 +20,14 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
import com.vaadin.terminal.gwt.client.VCaptionWrapper;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
/**
* Custom Layout implements complex layout defined with HTML template.
@@ -34,8 +35,8 @@ import com.vaadin.terminal.gwt.client.VCaptionWrapper;
* @author Vaadin Ltd
*
*/
-public class VCustomLayout extends ComplexPanel implements Paintable,
- Container, ContainerResizedListener {
+public class VCustomLayout extends ComplexPanel implements Container,
+ ContainerResizedListener {
public static final String CLASSNAME = "v-customlayout";
@@ -43,21 +44,21 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
private final HashMap<String, Element> locationToElement = new HashMap<String, Element>();
/** Location-name to contained widget map */
- private final HashMap<String, Widget> locationToWidget = new HashMap<String, Widget>();
+ final HashMap<String, Widget> locationToWidget = new HashMap<String, Widget>();
/** Widget to captionwrapper map */
- private final HashMap<Paintable, VCaptionWrapper> widgetToCaptionWrapper = new HashMap<Paintable, VCaptionWrapper>();
+ private final HashMap<VPaintableWidget, VCaptionWrapper> paintableToCaptionWrapper = new HashMap<VPaintableWidget, VCaptionWrapper>();
/** Name of the currently rendered style */
String currentTemplateName;
/** Unexecuted scripts loaded from the template */
- private String scripts = "";
+ String scripts = "";
/** Paintable ID of this paintable */
- private String pid;
+ String pid;
- private ApplicationConnection client;
+ ApplicationConnection client;
/** Has the template been loaded from contents passed in UIDL **/
private boolean hasTemplateContents = false;
@@ -131,64 +132,8 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
locationToWidget.put(location, widget);
}
- /** Update the layout from UIDL */
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
- // ApplicationConnection manages generic component features
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- pid = uidl.getId();
- if (!hasTemplate()) {
- // Update HTML template only once
- initializeHTML(uidl, client);
- }
-
- // Evaluate scripts
- eval(scripts);
- scripts = null;
-
- iLayout();
- // TODO Check if this is needed
- client.runDescendentsLayout(this);
-
- Set<Widget> oldWidgets = new HashSet<Widget>();
- oldWidgets.addAll(locationToWidget.values());
-
- // For all contained widgets
- for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) {
- final UIDL uidlForChild = (UIDL) i.next();
- if (uidlForChild.getTag().equals("location")) {
- final String location = uidlForChild.getStringAttribute("name");
- final Paintable child = client.getPaintable(uidlForChild
- .getChildUIDL(0));
- try {
- setWidget((Widget) child, location);
- child.updateFromUIDL(uidlForChild.getChildUIDL(0), client);
- } catch (final IllegalArgumentException e) {
- // If no location is found, this component is not visible
- }
- oldWidgets.remove(child);
- }
- }
- for (Iterator<Widget> iterator = oldWidgets.iterator(); iterator
- .hasNext();) {
- Widget oldWidget = iterator.next();
- if (oldWidget.isAttached()) {
- // slot of this widget is emptied, remove it
- remove(oldWidget);
- }
- }
-
- iLayout();
- // TODO Check if this is needed
- client.runDescendentsLayout(this);
-
- }
-
/** Initialize HTML-layout. */
- private void initializeHTML(UIDL uidl, ApplicationConnection client) {
+ void initializeHTML(UIDL uidl, ApplicationConnection client) {
final String newTemplateContents = uidl
.getStringAttribute("templateContents");
@@ -261,7 +206,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
return false;
}-*/;
- private boolean hasTemplate() {
+ boolean hasTemplate() {
if (currentTemplateName == null && !hasTemplateContents) {
return false;
} else {
@@ -292,7 +237,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
}
/** Evaluate given script in browser document */
- private static native void eval(String script)
+ static native void eval(String script)
/*-{
try {
if (script != null)
@@ -384,24 +329,26 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
}
/** Update caption for given widget */
- public void updateCaption(Paintable component, UIDL uidl) {
- VCaptionWrapper wrapper = widgetToCaptionWrapper.get(component);
+ public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
+ VCaptionWrapper wrapper = paintableToCaptionWrapper.get(paintable);
+ Widget widget = paintable.getWidgetForPaintable();
if (VCaption.isNeeded(uidl)) {
if (wrapper == null) {
- final String loc = getLocation((Widget) component);
- super.remove((Widget) component);
- wrapper = new VCaptionWrapper(component, client);
+ // Add a wrapper between the layout and the child widget
+ final String loc = getLocation(widget);
+ super.remove(widget);
+ wrapper = new VCaptionWrapper(paintable, client);
super.add(wrapper, locationToElement.get(loc));
- widgetToCaptionWrapper.put(component, wrapper);
+ paintableToCaptionWrapper.put(paintable, wrapper);
}
wrapper.updateCaption(uidl);
} else {
if (wrapper != null) {
- final String loc = getLocation((Widget) component);
+ // Remove the wrapper and add the widget directly to the layout
+ final String loc = getLocation(widget);
super.remove(wrapper);
- super.add((Widget) wrapper.getPaintable(),
- locationToElement.get(loc));
- widgetToCaptionWrapper.remove(component);
+ super.add(widget, locationToElement.get(loc));
+ paintableToCaptionWrapper.remove(paintable);
}
}
}
@@ -421,14 +368,15 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
/** Removes given widget from the layout */
@Override
public boolean remove(Widget w) {
- client.unregisterPaintable((Paintable) w);
+ VPaintableWidget paintable = VPaintableMap.get(client).getPaintable(w);
+ client.unregisterPaintable(paintable);
final String location = getLocation(w);
if (location != null) {
locationToWidget.remove(location);
}
- final VCaptionWrapper cw = widgetToCaptionWrapper.get(w);
+ final VCaptionWrapper cw = paintableToCaptionWrapper.get(paintable);
if (cw != null) {
- widgetToCaptionWrapper.remove(w);
+ paintableToCaptionWrapper.remove(paintable);
return super.remove(cw);
} else if (w != null) {
return super.remove(w);
@@ -447,7 +395,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
public void clear() {
super.clear();
locationToWidget.clear();
- widgetToCaptionWrapper.clear();
+ paintableToCaptionWrapper.clear();
}
public void iLayout() {
@@ -513,7 +461,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
}
}-*/;
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
updateRelativeSizedComponents(true, true);
if (width.equals("") || height.equals("")) {
@@ -642,4 +590,8 @@ public class VCustomLayout extends ComplexPanel implements Paintable,
return larger;
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomLayoutPaintable.java
new file mode 100644
index 0000000000..01190b39be
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCustomLayoutPaintable.java
@@ -0,0 +1,87 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VCustomLayoutPaintable extends VAbstractPaintableWidgetContainer {
+
+ /** Update the layout from UIDL */
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().client = client;
+ // ApplicationConnection manages generic component features
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ getWidgetForPaintable().pid = uidl.getId();
+ if (!getWidgetForPaintable().hasTemplate()) {
+ // Update HTML template only once
+ getWidgetForPaintable().initializeHTML(uidl, client);
+ }
+
+ // Evaluate scripts
+ VCustomLayout.eval(getWidgetForPaintable().scripts);
+ getWidgetForPaintable().scripts = null;
+
+ getWidgetForPaintable().iLayout();
+ // TODO Check if this is needed
+ client.runDescendentsLayout(getWidgetForPaintable());
+
+ Set<Widget> oldWidgets = new HashSet<Widget>();
+ oldWidgets.addAll(getWidgetForPaintable().locationToWidget.values());
+
+ // For all contained widgets
+ for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) {
+ final UIDL uidlForChild = (UIDL) i.next();
+ if (uidlForChild.getTag().equals("location")) {
+ final String location = uidlForChild.getStringAttribute("name");
+ UIDL childUIDL = uidlForChild.getChildUIDL(0);
+ final VPaintableWidget childPaintable = client
+ .getPaintable(childUIDL);
+ Widget childWidget = childPaintable.getWidgetForPaintable();
+ try {
+ getWidgetForPaintable().setWidget(childWidget, location);
+ childPaintable.updateFromUIDL(childUIDL, client);
+ } catch (final IllegalArgumentException e) {
+ // If no location is found, this component is not visible
+ }
+ oldWidgets.remove(childWidget);
+ }
+ }
+ for (Iterator<Widget> iterator = oldWidgets.iterator(); iterator
+ .hasNext();) {
+ Widget oldWidget = iterator.next();
+ if (oldWidget.isAttached()) {
+ // slot of this widget is emptied, remove it
+ getWidgetForPaintable().remove(oldWidget);
+ }
+ }
+
+ getWidgetForPaintable().iLayout();
+ // TODO Check if this is needed
+ client.runDescendentsLayout(getWidgetForPaintable());
+
+ }
+
+ @Override
+ public VCustomLayout getWidgetForPaintable() {
+ return (VCustomLayout) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VCustomLayout.class);
+ }
+
+ public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
+ getWidgetForPaintable().updateCaption(paintable, uidl);
+
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java b/src/com/vaadin/terminal/gwt/client/ui/VDateField.java
index bc228675b2..14c3b99210 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDateField.java
@@ -10,19 +10,15 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlowPanel;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.DateTimeService;
-import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VDateField extends FlowPanel implements Paintable, Field {
+public class VDateField extends FlowPanel implements Field {
public static final String CLASSNAME = "v-datefield";
- private String id;
+ protected String paintableId;
- private ApplicationConnection client;
+ protected ApplicationConnection client;
protected boolean immediate;
@@ -32,7 +28,6 @@ public class VDateField extends FlowPanel implements Paintable, Field {
public static final int RESOLUTION_HOUR = 8;
public static final int RESOLUTION_MIN = 16;
public static final int RESOLUTION_SEC = 32;
- public static final int RESOLUTION_MSEC = 64;
public static final String WEEK_NUMBERS = "wn";
@@ -65,7 +60,7 @@ public class VDateField extends FlowPanel implements Paintable, Field {
protected DateTimeService dts;
- private boolean showISOWeekNumbers = false;
+ protected boolean showISOWeekNumbers = false;
public VDateField() {
setStyleName(CLASSNAME);
@@ -77,84 +72,7 @@ public class VDateField extends FlowPanel implements Paintable, Field {
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, this);
- }
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // Ensure correct implementation and let layout manage caption
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- // Save details
- this.client = client;
- id = uidl.getId();
- immediate = uidl.getBooleanAttribute("immediate");
-
- readonly = uidl.getBooleanAttribute("readonly");
- enabled = !uidl.getBooleanAttribute("disabled");
-
- if (uidl.hasAttribute("locale")) {
- final String locale = uidl.getStringAttribute("locale");
- try {
- dts.setLocale(locale);
- currentLocale = locale;
- } catch (final LocaleNotLoadedException e) {
- currentLocale = dts.getLocale();
- VConsole.error("Tried to use an unloaded locale \"" + locale
- + "\". Using default locale (" + currentLocale + ").");
- VConsole.error(e);
- }
- }
-
- // We show week numbers only if the week starts with Monday, as ISO 8601
- // specifies
- showISOWeekNumbers = uidl.getBooleanAttribute(WEEK_NUMBERS)
- && dts.getFirstDayOfWeek() == 1;
-
- int newResolution;
- if (uidl.hasVariable("msec")) {
- newResolution = RESOLUTION_MSEC;
- } else if (uidl.hasVariable("sec")) {
- newResolution = RESOLUTION_SEC;
- } else if (uidl.hasVariable("min")) {
- newResolution = RESOLUTION_MIN;
- } else if (uidl.hasVariable("hour")) {
- newResolution = RESOLUTION_HOUR;
- } else if (uidl.hasVariable("day")) {
- newResolution = RESOLUTION_DAY;
- } else if (uidl.hasVariable("month")) {
- newResolution = RESOLUTION_MONTH;
- } else {
- newResolution = RESOLUTION_YEAR;
- }
-
- currentResolution = newResolution;
-
- // Add stylename that indicates current resolution
- addStyleName(CLASSNAME + "-" + resolutionToString(currentResolution));
-
- final int year = uidl.getIntVariable("year");
- final int month = (currentResolution >= RESOLUTION_MONTH) ? uidl
- .getIntVariable("month") : -1;
- final int day = (currentResolution >= RESOLUTION_DAY) ? uidl
- .getIntVariable("day") : -1;
- final int hour = (currentResolution >= RESOLUTION_HOUR) ? uidl
- .getIntVariable("hour") : 0;
- final int min = (currentResolution >= RESOLUTION_MIN) ? uidl
- .getIntVariable("min") : 0;
- final int sec = (currentResolution >= RESOLUTION_SEC) ? uidl
- .getIntVariable("sec") : 0;
- final int msec = (currentResolution >= RESOLUTION_MSEC) ? uidl
- .getIntVariable("msec") : 0;
-
- // Construct new date for this datefield (only if not null)
- if (year > -1) {
- setCurrentDate(new Date((long) getTime(year, month, day, hour, min,
- sec, msec)));
- } else {
- setCurrentDate(null);
+ client.handleWidgetTooltipEvent(event, this);
}
}
@@ -162,7 +80,7 @@ public class VDateField extends FlowPanel implements Paintable, Field {
* We need this redundant native function because Java's Date object doesn't
* have a setMilliseconds method.
*/
- private static native double getTime(int y, int m, int d, int h, int mi,
+ protected static native double getTime(int y, int m, int d, int h, int mi,
int s, int ms)
/*-{
try {
@@ -231,7 +149,7 @@ public class VDateField extends FlowPanel implements Paintable, Field {
}
public String getId() {
- return id;
+ return paintableId;
}
public ApplicationConnection getClient() {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java
index 91388edcaf..6bf1d4a3a7 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java
@@ -7,20 +7,16 @@ package com.vaadin.terminal.gwt.client.ui;
import java.util.Date;
import com.google.gwt.event.dom.client.DomEvent;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.DateTimeService;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener;
import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener;
import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener;
-import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener;
/**
* A client side implementation for InlineDateField
*/
public class VDateFieldCalendar extends VDateField {
- private final VCalendarPanel calendarPanel;
+ protected final VCalendarPanel calendarPanel;
public VDateFieldCalendar() {
super();
@@ -44,73 +40,11 @@ public class VDateFieldCalendar extends VDateField {
});
}
- @Override
- @SuppressWarnings("deprecation")
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- super.updateFromUIDL(uidl, client);
- calendarPanel.setShowISOWeekNumbers(isShowISOWeekNumbers());
- calendarPanel.setDateTimeService(getDateTimeService());
- calendarPanel.setResolution(getCurrentResolution());
- Date currentDate = getCurrentDate();
- if (currentDate != null) {
- calendarPanel.setDate(new Date(currentDate.getTime()));
- } else {
- calendarPanel.setDate(null);
- }
-
- if (currentResolution > RESOLUTION_DAY) {
- calendarPanel.setTimeChangeListener(new TimeChangeListener() {
- public void changed(int hour, int min, int sec, int msec) {
- Date d = getDate();
- if (d == null) {
- // date currently null, use the value from calendarPanel
- // (~ client time at the init of the widget)
- d = (Date) calendarPanel.getDate().clone();
- }
- d.setHours(hour);
- d.setMinutes(min);
- d.setSeconds(sec);
- DateTimeService.setMilliseconds(d, msec);
-
- // Always update time changes to the server
- calendarPanel.setDate(d);
- updateValueFromPanel();
- }
- });
- }
-
- if (currentResolution <= RESOLUTION_MONTH) {
- calendarPanel.setFocusChangeListener(new FocusChangeListener() {
- public void focusChanged(Date date) {
- Date date2 = new Date();
- if (calendarPanel.getDate() != null) {
- date2.setTime(calendarPanel.getDate().getTime());
- }
- /*
- * Update the value of calendarPanel
- */
- date2.setYear(date.getYear());
- date2.setMonth(date.getMonth());
- calendarPanel.setDate(date2);
- /*
- * Then update the value from panel to server
- */
- updateValueFromPanel();
- }
- });
- } else {
- calendarPanel.setFocusChangeListener(null);
- }
-
- // Update possible changes
- calendarPanel.renderCalendar();
- }
-
/**
* TODO refactor: almost same method as in VPopupCalendar.updateValue
*/
@SuppressWarnings("deprecation")
- private void updateValueFromPanel() {
+ protected void updateValueFromPanel() {
Date date2 = calendarPanel.getDate();
Date currentDate = getCurrentDate();
if (currentDate == null || date2.getTime() != currentDate.getTime()) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendarPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendarPaintable.java
new file mode 100644
index 0000000000..8dced06235
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendarPaintable.java
@@ -0,0 +1,101 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.DateTimeService;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener;
+
+public class VDateFieldCalendarPaintable extends VDateFieldPaintable {
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ super.updateFromUIDL(uidl, client);
+ getWidgetForPaintable().calendarPanel
+ .setShowISOWeekNumbers(getWidgetForPaintable()
+ .isShowISOWeekNumbers());
+ getWidgetForPaintable().calendarPanel
+ .setDateTimeService(getWidgetForPaintable()
+ .getDateTimeService());
+ getWidgetForPaintable().calendarPanel
+ .setResolution(getWidgetForPaintable().getCurrentResolution());
+ Date currentDate = getWidgetForPaintable().getCurrentDate();
+ if (currentDate != null) {
+ getWidgetForPaintable().calendarPanel.setDate(new Date(currentDate
+ .getTime()));
+ } else {
+ getWidgetForPaintable().calendarPanel.setDate(null);
+ }
+
+ if (getWidgetForPaintable().currentResolution > VDateField.RESOLUTION_DAY) {
+ getWidgetForPaintable().calendarPanel
+ .setTimeChangeListener(new TimeChangeListener() {
+ public void changed(int hour, int min, int sec, int msec) {
+ Date d = getWidgetForPaintable().getDate();
+ if (d == null) {
+ // date currently null, use the value from
+ // calendarPanel
+ // (~ client time at the init of the widget)
+ d = (Date) getWidgetForPaintable().calendarPanel
+ .getDate().clone();
+ }
+ d.setHours(hour);
+ d.setMinutes(min);
+ d.setSeconds(sec);
+ DateTimeService.setMilliseconds(d, msec);
+
+ // Always update time changes to the server
+ getWidgetForPaintable().calendarPanel.setDate(d);
+ getWidgetForPaintable().updateValueFromPanel();
+ }
+ });
+ }
+
+ if (getWidgetForPaintable().currentResolution <= VDateField.RESOLUTION_MONTH) {
+ getWidgetForPaintable().calendarPanel
+ .setFocusChangeListener(new FocusChangeListener() {
+ public void focusChanged(Date date) {
+ Date date2 = new Date();
+ if (getWidgetForPaintable().calendarPanel.getDate() != null) {
+ date2.setTime(getWidgetForPaintable().calendarPanel
+ .getDate().getTime());
+ }
+ /*
+ * Update the value of calendarPanel
+ */
+ date2.setYear(date.getYear());
+ date2.setMonth(date.getMonth());
+ getWidgetForPaintable().calendarPanel
+ .setDate(date2);
+ /*
+ * Then update the value from panel to server
+ */
+ getWidgetForPaintable().updateValueFromPanel();
+ }
+ });
+ } else {
+ getWidgetForPaintable().calendarPanel.setFocusChangeListener(null);
+ }
+
+ // Update possible changes
+ getWidgetForPaintable().calendarPanel.renderCalendar();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VDateFieldCalendar.class);
+ }
+
+ @Override
+ public VDateFieldCalendar getWidgetForPaintable() {
+ return (VDateFieldCalendar) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldPaintable.java
new file mode 100644
index 0000000000..4aaf1c2dd3
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldPaintable.java
@@ -0,0 +1,106 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VConsole;
+
+public class VDateFieldPaintable extends VAbstractPaintableWidget {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Ensure correct implementation and let layout manage caption
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ // Save details
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getId();
+ getWidgetForPaintable().immediate = uidl
+ .getBooleanAttribute("immediate");
+
+ getWidgetForPaintable().readonly = uidl.getBooleanAttribute("readonly");
+ getWidgetForPaintable().enabled = !uidl.getBooleanAttribute("disabled");
+
+ if (uidl.hasAttribute("locale")) {
+ final String locale = uidl.getStringAttribute("locale");
+ try {
+ getWidgetForPaintable().dts.setLocale(locale);
+ getWidgetForPaintable().currentLocale = locale;
+ } catch (final LocaleNotLoadedException e) {
+ getWidgetForPaintable().currentLocale = getWidgetForPaintable().dts
+ .getLocale();
+ VConsole.error("Tried to use an unloaded locale \"" + locale
+ + "\". Using default locale ("
+ + getWidgetForPaintable().currentLocale + ").");
+ VConsole.error(e);
+ }
+ }
+
+ // We show week numbers only if the week starts with Monday, as ISO 8601
+ // specifies
+ getWidgetForPaintable().showISOWeekNumbers = uidl
+ .getBooleanAttribute(VDateField.WEEK_NUMBERS)
+ && getWidgetForPaintable().dts.getFirstDayOfWeek() == 1;
+
+ int newResolution;
+ if (uidl.hasVariable("sec")) {
+ newResolution = VDateField.RESOLUTION_SEC;
+ } else if (uidl.hasVariable("min")) {
+ newResolution = VDateField.RESOLUTION_MIN;
+ } else if (uidl.hasVariable("hour")) {
+ newResolution = VDateField.RESOLUTION_HOUR;
+ } else if (uidl.hasVariable("day")) {
+ newResolution = VDateField.RESOLUTION_DAY;
+ } else if (uidl.hasVariable("month")) {
+ newResolution = VDateField.RESOLUTION_MONTH;
+ } else {
+ newResolution = VDateField.RESOLUTION_YEAR;
+ }
+
+ getWidgetForPaintable().currentResolution = newResolution;
+
+ // Add stylename that indicates current resolution
+ getWidgetForPaintable()
+ .addStyleName(
+ VDateField.CLASSNAME
+ + "-"
+ + VDateField
+ .resolutionToString(getWidgetForPaintable().currentResolution));
+
+ final int year = uidl.getIntVariable("year");
+ final int month = (getWidgetForPaintable().currentResolution >= VDateField.RESOLUTION_MONTH) ? uidl
+ .getIntVariable("month") : -1;
+ final int day = (getWidgetForPaintable().currentResolution >= VDateField.RESOLUTION_DAY) ? uidl
+ .getIntVariable("day") : -1;
+ final int hour = (getWidgetForPaintable().currentResolution >= VDateField.RESOLUTION_HOUR) ? uidl
+ .getIntVariable("hour") : 0;
+ final int min = (getWidgetForPaintable().currentResolution >= VDateField.RESOLUTION_MIN) ? uidl
+ .getIntVariable("min") : 0;
+ final int sec = (getWidgetForPaintable().currentResolution >= VDateField.RESOLUTION_SEC) ? uidl
+ .getIntVariable("sec") : 0;
+
+ // Construct new date for this datefield (only if not null)
+ if (year > -1) {
+ getWidgetForPaintable().setCurrentDate(
+ new Date((long) getWidgetForPaintable().getTime(year,
+ month, day, hour, min, sec, 0)));
+ } else {
+ getWidgetForPaintable().setCurrentDate(null);
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VDateField.class);
+ }
+
+ @Override
+ public VDateField getWidgetForPaintable() {
+ return (VDateField) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
index 072754e0ce..0297e8df3f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
@@ -4,10 +4,8 @@
package com.vaadin.terminal.gwt.client.ui;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArrayString;
@@ -26,12 +24,13 @@ import com.google.gwt.xhr.client.ReadyStateChangeHandler;
import com.google.gwt.xhr.client.XMLHttpRequest;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintable;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.VTooltip;
import com.vaadin.terminal.gwt.client.ValueMap;
import com.vaadin.terminal.gwt.client.ui.dd.DDUtil;
@@ -95,7 +94,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
}
@@ -109,16 +108,12 @@ public class VDragAndDropWrapper extends VCustomComponent implements
private boolean startDrag(NativeEvent event) {
if (dragStartMode == WRAPPER || dragStartMode == COMPONENT) {
VTransferable transferable = new VTransferable();
- transferable.setDragSource(VDragAndDropWrapper.this);
-
- Paintable paintable;
- Widget w = Util.findWidget((Element) event.getEventTarget().cast(),
- null);
- while (w != null && !(w instanceof Paintable)) {
- w = w.getParent();
- }
- paintable = (Paintable) w;
+ transferable.setDragSource(VPaintableMap.get(client).getPaintable(
+ VDragAndDropWrapper.this));
+ VPaintableWidget paintable = Util.findPaintable(client,
+ (Element) event.getEventTarget().cast());
+ Widget widget = paintable.getWidgetForPaintable();
transferable.setData("component", paintable);
VDragEvent dragEvent = VDragAndDropManager.get().startDrag(
transferable, event, true);
@@ -129,8 +124,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
if (dragStartMode == WRAPPER) {
dragEvent.createDragImage(getElement(), true);
} else {
- dragEvent.createDragImage(((Widget) paintable).getElement(),
- true);
+ dragEvent.createDragImage(widget.getElement(), true);
}
return true;
}
@@ -144,58 +138,15 @@ public class VDragAndDropWrapper extends VCustomComponent implements
protected int dragStartMode;
- private ApplicationConnection client;
- private VAbstractDropHandler dropHandler;
+ ApplicationConnection client;
+ VAbstractDropHandler dropHandler;
private VDragEvent vaadinDragEvent;
- private int filecounter = 0;
- private Map<String, String> fileIdToReceiver;
- private ValueMap html5DataFlavors;
+ int filecounter = 0;
+ Map<String, String> fileIdToReceiver;
+ ValueMap html5DataFlavors;
private Element dragStartElement;
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
- super.updateFromUIDL(uidl, client);
- if (!uidl.hasAttribute("cached") && !uidl.hasAttribute("hidden")) {
- UIDL acceptCrit = uidl.getChildByTagName("-ac");
- if (acceptCrit == null) {
- dropHandler = null;
- } else {
- if (dropHandler == null) {
- dropHandler = new CustomDropHandler();
- }
- dropHandler.updateAcceptRules(acceptCrit);
- }
-
- Set<String> variableNames = uidl.getVariableNames();
- for (String fileId : variableNames) {
- if (fileId.startsWith("rec-")) {
- String receiverUrl = uidl.getStringVariable(fileId);
- fileId = fileId.substring(4);
- if (fileIdToReceiver == null) {
- fileIdToReceiver = new HashMap<String, String>();
- }
- if ("".equals(receiverUrl)) {
- Integer id = Integer.parseInt(fileId);
- int indexOf = fileIds.indexOf(id);
- if (indexOf != -1) {
- files.remove(indexOf);
- fileIds.remove(indexOf);
- }
- } else {
- fileIdToReceiver.put(fileId, receiverUrl);
- }
- }
- }
- startNextUpload();
-
- dragStartMode = uidl.getIntAttribute(DRAG_START_MODE);
- initDragStartMode();
- html5DataFlavors = uidl.getMapAttribute(HTML5_DATA_FLAVORS);
- }
- }
-
protected void initDragStartMode() {
Element div = getElement();
if (dragStartMode == HTML5) {
@@ -235,7 +186,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
};
private Timer dragleavetimer;
- private void startNextUpload() {
+ void startNextUpload() {
Scheduler.get().scheduleDeferred(new Command() {
public void execute() {
@@ -291,7 +242,8 @@ public class VDragAndDropWrapper extends VCustomComponent implements
}
if (VDragAndDropManager.get().getCurrentDropHandler() != getDropHandler()) {
VTransferable transferable = new VTransferable();
- transferable.setDragSource(this);
+ transferable.setDragSource(VPaintableMap.get(client)
+ .getPaintable(this));
vaadinDragEvent = VDragAndDropManager.get().startDrag(
transferable, event, false);
@@ -459,8 +411,8 @@ public class VDragAndDropWrapper extends VCustomComponent implements
* @param fileId
* @param data
*/
- private List<Integer> fileIds = new ArrayList<Integer>();
- private List<VHtml5File> files = new ArrayList<VHtml5File>();
+ List<Integer> fileIds = new ArrayList<Integer>();
+ List<VHtml5File> files = new ArrayList<VHtml5File>();
private void queueFilePost(final int fileId, final VHtml5File file) {
fileIds.add(fileId);
@@ -468,7 +420,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
}
private String getPid() {
- return client.getPid(this);
+ return VPaintableMap.get(client).getPid((VPaintable) this);
}
public VDropHandler getDropHandler() {
@@ -547,8 +499,9 @@ public class VDragAndDropWrapper extends VCustomComponent implements
}
@Override
- public Paintable getPaintable() {
- return VDragAndDropWrapper.this;
+ public VPaintableWidget getPaintable() {
+ return VPaintableMap.get(client).getPaintable(
+ VDragAndDropWrapper.this);
}
public ApplicationConnection getApplicationConnection() {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperIE.java b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperIE.java
index ce4a19462f..438ec49873 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperIE.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperIE.java
@@ -1,4 +1,4 @@
-/*
+/*
@VaadinApache2LicenseForJavaFiles@
*/
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperPaintable.java
new file mode 100644
index 0000000000..2a3189d9ba
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperPaintable.java
@@ -0,0 +1,71 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VDragAndDropWrapperPaintable extends VCustomComponentPaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().client = client;
+ super.updateFromUIDL(uidl, client);
+ if (!uidl.hasAttribute("cached") && !uidl.hasAttribute("hidden")) {
+ UIDL acceptCrit = uidl.getChildByTagName("-ac");
+ if (acceptCrit == null) {
+ getWidgetForPaintable().dropHandler = null;
+ } else {
+ if (getWidgetForPaintable().dropHandler == null) {
+ getWidgetForPaintable().dropHandler = getWidgetForPaintable().new CustomDropHandler();
+ }
+ getWidgetForPaintable().dropHandler
+ .updateAcceptRules(acceptCrit);
+ }
+
+ Set<String> variableNames = uidl.getVariableNames();
+ for (String fileId : variableNames) {
+ if (fileId.startsWith("rec-")) {
+ String receiverUrl = uidl.getStringVariable(fileId);
+ fileId = fileId.substring(4);
+ if (getWidgetForPaintable().fileIdToReceiver == null) {
+ getWidgetForPaintable().fileIdToReceiver = new HashMap<String, String>();
+ }
+ if ("".equals(receiverUrl)) {
+ Integer id = Integer.parseInt(fileId);
+ int indexOf = getWidgetForPaintable().fileIds
+ .indexOf(id);
+ if (indexOf != -1) {
+ getWidgetForPaintable().files.remove(indexOf);
+ getWidgetForPaintable().fileIds.remove(indexOf);
+ }
+ } else {
+ getWidgetForPaintable().fileIdToReceiver.put(fileId,
+ receiverUrl);
+ }
+ }
+ }
+ getWidgetForPaintable().startNextUpload();
+
+ getWidgetForPaintable().dragStartMode = uidl
+ .getIntAttribute(VDragAndDropWrapper.DRAG_START_MODE);
+ getWidgetForPaintable().initDragStartMode();
+ getWidgetForPaintable().html5DataFlavors = uidl
+ .getMapAttribute(VDragAndDropWrapper.HTML5_DATA_FLAVORS);
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VDragAndDropWrapper.class);
+ }
+
+ @Override
+ public VDragAndDropWrapper getWidgetForPaintable() {
+ return (VDragAndDropWrapper) super.getWidgetForPaintable();
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
index 17a95388b9..549a7b4549 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
@@ -8,190 +8,31 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.ObjectElement;
-import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.event.dom.client.DomEvent.Type;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.HTML;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VConsole;
-import com.vaadin.terminal.gwt.client.VTooltip;
-public class VEmbedded extends HTML implements Paintable {
- public static final String CLICK_EVENT_IDENTIFIER = "click";
+public class VEmbedded extends HTML {
+ public static String CLASSNAME = "v-embedded";
- private static String CLASSNAME = "v-embedded";
+ protected String height;
+ protected String width;
+ protected Element browserElement;
- private String height;
- private String width;
- private Element browserElement;
+ protected String type;
- private String type;
-
- private ApplicationConnection client;
-
- private final ClickEventHandler clickEventHandler = new ClickEventHandler(
- this, CLICK_EVENT_IDENTIFIER) {
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
-
- };
+ protected ApplicationConnection client;
public VEmbedded() {
setStyleName(CLASSNAME);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
- this.client = client;
-
- boolean clearBrowserElement = true;
-
- clickEventHandler.handleEventHandlerRegistration(client);
-
- if (uidl.hasAttribute("type")) {
- type = uidl.getStringAttribute("type");
- if (type.equals("image")) {
- addStyleName(CLASSNAME + "-image");
- Element el = null;
- boolean created = false;
- NodeList<Node> nodes = getElement().getChildNodes();
- if (nodes != null && nodes.getLength() == 1) {
- Node n = nodes.getItem(0);
- if (n.getNodeType() == Node.ELEMENT_NODE) {
- Element e = (Element) n;
- if (e.getTagName().equals("IMG")) {
- el = e;
- }
- }
- }
- if (el == null) {
- setHTML("");
- el = DOM.createImg();
- created = true;
- client.addPngFix(el);
- DOM.sinkEvents(el, Event.ONLOAD);
- }
-
- // Set attributes
- Style style = el.getStyle();
- String w = uidl.getStringAttribute("width");
- if (w != null) {
- style.setProperty("width", w);
- } else {
- style.setProperty("width", "");
- }
- String h = uidl.getStringAttribute("height");
- if (h != null) {
- style.setProperty("height", h);
- } else {
- style.setProperty("height", "");
- }
- DOM.setElementProperty(el, "src", getSrc(uidl, client));
-
- if (created) {
- // insert in dom late
- getElement().appendChild(el);
- }
-
- /*
- * Sink tooltip events so tooltip is displayed when hovering the
- * image.
- */
- sinkEvents(VTooltip.TOOLTIP_EVENTS);
-
- } else if (type.equals("browser")) {
- addStyleName(CLASSNAME + "-browser");
- if (browserElement == null) {
- setHTML("<iframe width=\"100%\" height=\"100%\" frameborder=\"0\""
- + " allowTransparency=\"true\" src=\"\""
- + " name=\"" + uidl.getId() + "\"></iframe>");
- browserElement = DOM.getFirstChild(getElement());
- }
- DOM.setElementAttribute(browserElement, "src",
- getSrc(uidl, client));
- clearBrowserElement = false;
- } else {
- VConsole.log("Unknown Embedded type '" + type + "'");
- }
- } else if (uidl.hasAttribute("mimetype")) {
- final String mime = uidl.getStringAttribute("mimetype");
- if (mime.equals("application/x-shockwave-flash")) {
- // Handle embedding of Flash
- addStyleName(CLASSNAME + "-flash");
- setHTML(createFlashEmbed(uidl));
-
- } else if (mime.equals("image/svg+xml")) {
- addStyleName(CLASSNAME + "-svg");
- String data;
- Map<String, String> parameters = getParameters(uidl);
- if (parameters.get("data") == null) {
- data = getSrc(uidl, client);
- } else {
- data = "data:image/svg+xml," + parameters.get("data");
- }
- setHTML("");
- ObjectElement obj = Document.get().createObjectElement();
- obj.setType(mime);
- obj.setData(data);
- if (width != null) {
- obj.getStyle().setProperty("width", "100%");
- }
- if (height != null) {
- obj.getStyle().setProperty("height", "100%");
- }
- if (uidl.hasAttribute("classid")) {
- obj.setAttribute("classid",
- uidl.getStringAttribute("classid"));
- }
- if (uidl.hasAttribute("codebase")) {
- obj.setAttribute("codebase",
- uidl.getStringAttribute("codebase"));
- }
- if (uidl.hasAttribute("codetype")) {
- obj.setAttribute("codetype",
- uidl.getStringAttribute("codetype"));
- }
- if (uidl.hasAttribute("archive")) {
- obj.setAttribute("archive",
- uidl.getStringAttribute("archive"));
- }
- if (uidl.hasAttribute("standby")) {
- obj.setAttribute("standby",
- uidl.getStringAttribute("standby"));
- }
- getElement().appendChild(obj);
-
- } else {
- VConsole.log("Unknown Embedded mimetype '" + mime + "'");
- }
- } else {
- VConsole.log("Unknown Embedded; no type or mimetype attribute");
- }
-
- if (clearBrowserElement) {
- browserElement = null;
- }
- }
-
/**
* Creates the Object and Embed tags for the Flash plugin so it works
* cross-browser
@@ -200,7 +41,7 @@ public class VEmbedded extends HTML implements Paintable {
* The UIDL
* @return Tags concatenated into a string
*/
- private String createFlashEmbed(UIDL uidl) {
+ protected String createFlashEmbed(UIDL uidl) {
/*
* To ensure cross-browser compatibility we are using the twice-cooked
* method to embed flash i.e. we add a OBJECT tag for IE ActiveX and
@@ -318,7 +159,7 @@ public class VEmbedded extends HTML implements Paintable {
* @param uidl
* @return
*/
- private static Map<String, String> getParameters(UIDL uidl) {
+ protected static Map<String, String> getParameters(UIDL uidl) {
Map<String, String> parameters = new HashMap<String, String>();
Iterator<Object> childIterator = uidl.getChildIterator();
@@ -347,7 +188,7 @@ public class VEmbedded extends HTML implements Paintable {
* @param client
* @return
*/
- private String getSrc(UIDL uidl, ApplicationConnection client) {
+ protected String getSrc(UIDL uidl, ApplicationConnection client) {
String url = client.translateVaadinUri(uidl.getStringAttribute("src"));
if (url == null) {
return "";
@@ -412,7 +253,7 @@ public class VEmbedded extends HTML implements Paintable {
Util.notifyParentOfSizeChange(this, true);
}
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
/**
@@ -432,5 +273,4 @@ public class VEmbedded extends HTML implements Paintable {
Unit.PX);
}
}
-
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VEmbeddedPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VEmbeddedPaintable.java
new file mode 100644
index 0000000000..bdb34b6d14
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VEmbeddedPaintable.java
@@ -0,0 +1,198 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.ObjectElement;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VTooltip;
+
+public class VEmbeddedPaintable extends VAbstractPaintableWidget {
+
+ public static final String CLICK_EVENT_IDENTIFIER = "click";
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ // Save details
+ getWidgetForPaintable().client = client;
+
+ boolean clearBrowserElement = true;
+
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ if (uidl.hasAttribute("type")) {
+ getWidgetForPaintable().type = uidl.getStringAttribute("type");
+ if (getWidgetForPaintable().type.equals("image")) {
+ getWidgetForPaintable().addStyleName(
+ VEmbedded.CLASSNAME + "-image");
+ Element el = null;
+ boolean created = false;
+ NodeList<Node> nodes = getWidgetForPaintable().getElement()
+ .getChildNodes();
+ if (nodes != null && nodes.getLength() == 1) {
+ Node n = nodes.getItem(0);
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ Element e = (Element) n;
+ if (e.getTagName().equals("IMG")) {
+ el = e;
+ }
+ }
+ }
+ if (el == null) {
+ getWidgetForPaintable().setHTML("");
+ el = DOM.createImg();
+ created = true;
+ DOM.sinkEvents(el, Event.ONLOAD);
+ }
+
+ // Set attributes
+ Style style = el.getStyle();
+ String w = uidl.getStringAttribute("width");
+ if (w != null) {
+ style.setProperty("width", w);
+ } else {
+ style.setProperty("width", "");
+ }
+ String h = uidl.getStringAttribute("height");
+ if (h != null) {
+ style.setProperty("height", h);
+ } else {
+ style.setProperty("height", "");
+ }
+ DOM.setElementProperty(el, "src", getWidgetForPaintable()
+ .getSrc(uidl, client));
+
+ if (created) {
+ // insert in dom late
+ getWidgetForPaintable().getElement().appendChild(el);
+ }
+
+ /*
+ * Sink tooltip events so tooltip is displayed when hovering the
+ * image.
+ */
+ getWidgetForPaintable().sinkEvents(VTooltip.TOOLTIP_EVENTS);
+
+ } else if (getWidgetForPaintable().type.equals("browser")) {
+ getWidgetForPaintable().addStyleName(
+ VEmbedded.CLASSNAME + "-browser");
+ if (getWidgetForPaintable().browserElement == null) {
+ getWidgetForPaintable().setHTML(
+ "<iframe width=\"100%\" height=\"100%\" frameborder=\"0\""
+ + " allowTransparency=\"true\" src=\"\""
+ + " name=\"" + uidl.getId()
+ + "\"></iframe>");
+ getWidgetForPaintable().browserElement = DOM
+ .getFirstChild(getWidgetForPaintable().getElement());
+ }
+ DOM.setElementAttribute(getWidgetForPaintable().browserElement,
+ "src", getWidgetForPaintable().getSrc(uidl, client));
+ clearBrowserElement = false;
+ } else {
+ VConsole.log("Unknown Embedded type '"
+ + getWidgetForPaintable().type + "'");
+ }
+ } else if (uidl.hasAttribute("mimetype")) {
+ final String mime = uidl.getStringAttribute("mimetype");
+ if (mime.equals("application/x-shockwave-flash")) {
+ // Handle embedding of Flash
+ getWidgetForPaintable().addStyleName(
+ VEmbedded.CLASSNAME + "-flash");
+ getWidgetForPaintable().setHTML(
+ getWidgetForPaintable().createFlashEmbed(uidl));
+
+ } else if (mime.equals("image/svg+xml")) {
+ getWidgetForPaintable().addStyleName(
+ VEmbedded.CLASSNAME + "-svg");
+ String data;
+ Map<String, String> parameters = VEmbedded.getParameters(uidl);
+ if (parameters.get("data") == null) {
+ data = getWidgetForPaintable().getSrc(uidl, client);
+ } else {
+ data = "data:image/svg+xml," + parameters.get("data");
+ }
+ getWidgetForPaintable().setHTML("");
+ ObjectElement obj = Document.get().createObjectElement();
+ obj.setType(mime);
+ obj.setData(data);
+ if (getWidgetForPaintable().width != null) {
+ obj.getStyle().setProperty("width", "100%");
+ }
+ if (getWidgetForPaintable().height != null) {
+ obj.getStyle().setProperty("height", "100%");
+ }
+ if (uidl.hasAttribute("classid")) {
+ obj.setAttribute("classid",
+ uidl.getStringAttribute("classid"));
+ }
+ if (uidl.hasAttribute("codebase")) {
+ obj.setAttribute("codebase",
+ uidl.getStringAttribute("codebase"));
+ }
+ if (uidl.hasAttribute("codetype")) {
+ obj.setAttribute("codetype",
+ uidl.getStringAttribute("codetype"));
+ }
+ if (uidl.hasAttribute("archive")) {
+ obj.setAttribute("archive",
+ uidl.getStringAttribute("archive"));
+ }
+ if (uidl.hasAttribute("standby")) {
+ obj.setAttribute("standby",
+ uidl.getStringAttribute("standby"));
+ }
+ getWidgetForPaintable().getElement().appendChild(obj);
+
+ } else {
+ VConsole.log("Unknown Embedded mimetype '" + mime + "'");
+ }
+ } else {
+ VConsole.log("Unknown Embedded; no type or mimetype attribute");
+ }
+
+ if (clearBrowserElement) {
+ getWidgetForPaintable().browserElement = null;
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VEmbedded.class);
+ }
+
+ @Override
+ public VEmbedded getWidgetForPaintable() {
+ return (VEmbedded) super.getWidgetForPaintable();
+ }
+
+ protected final ClickEventHandler clickEventHandler = new ClickEventHandler(
+ this, CLICK_EVENT_IDENTIFIER) {
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+
+ };
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
index 9a6cbdcd9b..7006a82fd1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
@@ -12,9 +12,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
-import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -48,7 +46,6 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.EventId;
import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
@@ -60,9 +57,8 @@ import com.vaadin.terminal.gwt.client.VTooltip;
* TODO needs major refactoring (to be extensible etc)
*/
@SuppressWarnings("deprecation")
-public class VFilterSelect extends Composite implements Paintable, Field,
- KeyDownHandler, KeyUpHandler, ClickHandler, FocusHandler, BlurHandler,
- Focusable {
+public class VFilterSelect extends Composite implements Field, KeyDownHandler,
+ KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable {
/**
* Represents a suggestion in the suggestion popup box
@@ -154,7 +150,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
private static final String Z_INDEX = "30000";
- private final SuggestionMenu menu;
+ protected final SuggestionMenu menu;
private final Element up = DOM.createDiv();
private final Element down = DOM.createDiv();
@@ -762,12 +758,6 @@ public class VFilterSelect extends Composite implements Paintable, Field,
}
public void onLoad(LoadEvent event) {
- if (BrowserInfo.get().isIE6()) {
- // Ensure PNG transparency works in IE6
- Util.doIE6PngFix((Element) Element.as(event.getNativeEvent()
- .getEventTarget()));
- }
-
// Handle icon onload events to ensure shadow is resized
// correctly
delayedImageLoadExecutioner.trigger();
@@ -783,7 +773,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
return keyboardSelectedItem;
}
- private void setKeyboardSelectedItem(MenuItem firstItem) {
+ protected void setKeyboardSelectedItem(MenuItem firstItem) {
keyboardSelectedItem = firstItem;
}
@@ -810,7 +800,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
/**
* The text box where the filter is written
*/
- private final TextBox tb = new TextBox() {
+ protected final TextBox tb = new TextBox() {
/*
* (non-Javadoc)
*
@@ -822,7 +812,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, VFilterSelect.this);
+ client.handleWidgetTooltipEvent(event, VFilterSelect.this);
}
}
@@ -837,7 +827,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
};
};
- private final SuggestionPopup suggestionPopup = new SuggestionPopup();
+ protected final SuggestionPopup suggestionPopup = new SuggestionPopup();
/**
* Used when measuring the width of the popup
@@ -855,7 +845,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, VFilterSelect.this);
+ client.handleWidgetTooltipEvent(event, VFilterSelect.this);
}
/*
@@ -868,73 +858,73 @@ public class VFilterSelect extends Composite implements Paintable, Field,
private final Image selectedItemIcon = new Image();
- private ApplicationConnection client;
+ protected ApplicationConnection client;
- private String paintableId;
+ protected String paintableId;
- private int currentPage;
+ protected int currentPage;
/**
* A collection of available suggestions (options) as received from the
* server.
*/
- private final List<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>();
+ protected final List<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>();
- private boolean immediate;
+ protected boolean immediate;
- private String selectedOptionKey;
+ protected String selectedOptionKey;
- private boolean waitingForFilteringResponse = false;
- private boolean updateSelectionWhenReponseIsReceived = false;
+ protected boolean waitingForFilteringResponse = false;
+ protected boolean updateSelectionWhenReponseIsReceived = false;
private boolean tabPressedWhenPopupOpen = false;
- private boolean initDone = false;
+ protected boolean initDone = false;
- private String lastFilter = "";
+ protected String lastFilter = "";
- private enum Select {
+ protected enum Select {
NONE, FIRST, LAST
};
- private Select selectPopupItemWhenResponseIsReceived = Select.NONE;
+ protected Select selectPopupItemWhenResponseIsReceived = Select.NONE;
/**
* The current suggestion selected from the dropdown. This is one of the
* values in currentSuggestions except when filtering, in this case
* currentSuggestion might not be in currentSuggestions.
*/
- private FilterSelectSuggestion currentSuggestion;
+ protected FilterSelectSuggestion currentSuggestion;
- private int totalMatches;
- private boolean allowNewItem;
- private boolean nullSelectionAllowed;
- private boolean nullSelectItem;
- private boolean enabled;
- private boolean readonly;
+ protected int totalMatches;
+ protected boolean allowNewItem;
+ protected boolean nullSelectionAllowed;
+ protected boolean nullSelectItem;
+ protected boolean enabled;
+ protected boolean readonly;
- private int filteringmode = FILTERINGMODE_OFF;
+ protected int filteringmode = FILTERINGMODE_OFF;
// shown in unfocused empty field, disappears on focus (e.g "Search here")
private static final String CLASSNAME_PROMPT = "prompt";
- private static final String ATTR_INPUTPROMPT = "prompt";
+ protected static final String ATTR_INPUTPROMPT = "prompt";
public static final String ATTR_NO_TEXT_INPUT = "noInput";
- private String inputPrompt = "";
- private boolean prompting = false;
+ protected String inputPrompt = "";
+ protected boolean prompting = false;
// Set true when popupopened has been clicked. Cleared on each UIDL-update.
// This handles the special case where are not filtering yet and the
// selected value has changed on the server-side. See #2119
- private boolean popupOpenerClicked;
+ protected boolean popupOpenerClicked;
private String width = null;
private int textboxPadding = -1;
private int componentPadding = -1;
- private int suggestionPopupMinWidth = 0;
+ protected int suggestionPopupMinWidth = 0;
private int popupWidth = -1;
/*
* Stores the last new item string to avoid double submissions. Cleared on
* uidl updates
*/
- private String lastNewItemString;
- private boolean focused = false;
+ protected String lastNewItemString;
+ protected boolean focused = false;
private int horizPaddingAndBorder = 2;
/**
@@ -1037,204 +1027,11 @@ public class VFilterSelect extends Composite implements Paintable, Field,
currentPage = page;
}
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
- * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
- */
- @SuppressWarnings("deprecation")
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- paintableId = uidl.getId();
- this.client = client;
-
- readonly = uidl.hasAttribute("readonly");
- enabled = !uidl.hasAttribute("disabled");
-
- tb.setEnabled(enabled);
- updateReadOnly();
-
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- // Inverse logic here to make the default case (text input enabled)
- // work without additional UIDL messages
- boolean noTextInput = uidl.hasAttribute(ATTR_NO_TEXT_INPUT)
- && uidl.getBooleanAttribute(ATTR_NO_TEXT_INPUT);
- setTextInputEnabled(!noTextInput);
-
- // not a FocusWidget -> needs own tabindex handling
- if (uidl.hasAttribute("tabindex")) {
- tb.setTabIndex(uidl.getIntAttribute("tabindex"));
- }
-
- if (uidl.hasAttribute("filteringmode")) {
- filteringmode = uidl.getIntAttribute("filteringmode");
- }
-
- immediate = uidl.hasAttribute("immediate");
-
- nullSelectionAllowed = uidl.hasAttribute("nullselect");
-
- nullSelectItem = uidl.hasAttribute("nullselectitem")
- && uidl.getBooleanAttribute("nullselectitem");
-
- currentPage = uidl.getIntVariable("page");
-
- if (uidl.hasAttribute("pagelength")) {
- pageLength = uidl.getIntAttribute("pagelength");
- }
-
- if (uidl.hasAttribute(ATTR_INPUTPROMPT)) {
- // input prompt changed from server
- inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
- } else {
- inputPrompt = "";
- }
-
- suggestionPopup.updateStyleNames(uidl);
-
- allowNewItem = uidl.hasAttribute("allownewitem");
- lastNewItemString = null;
-
- currentSuggestions.clear();
- if (!waitingForFilteringResponse) {
- /*
- * Clear the current suggestions as the server response always
- * includes the new ones. Exception is when filtering, then we need
- * to retain the value if the user does not select any of the
- * options matching the filter.
- */
- currentSuggestion = null;
- /*
- * Also ensure no old items in menu. Unless cleared the old values
- * may cause odd effects on blur events. Suggestions in menu might
- * not necessary exist in select at all anymore.
- */
- suggestionPopup.menu.clearItems();
-
- }
-
- final UIDL options = uidl.getChildUIDL(0);
- if (uidl.hasAttribute("totalMatches")) {
- totalMatches = uidl.getIntAttribute("totalMatches");
- } else {
- totalMatches = 0;
- }
-
- // used only to calculate minimum popup width
- String captions = Util.escapeHTML(inputPrompt);
-
- for (final Iterator<?> i = options.getChildIterator(); i.hasNext();) {
- final UIDL optionUidl = (UIDL) i.next();
- final FilterSelectSuggestion suggestion = new FilterSelectSuggestion(
- optionUidl);
- currentSuggestions.add(suggestion);
- if (optionUidl.hasAttribute("selected")) {
- if (!waitingForFilteringResponse || popupOpenerClicked) {
- String newSelectedOptionKey = Integer.toString(suggestion
- .getOptionKey());
- if (!newSelectedOptionKey.equals(selectedOptionKey)
- || suggestion.getReplacementString().equals(
- tb.getText())) {
- // Update text field if we've got a new selection
- // Also update if we've got the same text to retain old
- // text selection behavior
- setPromptingOff(suggestion.getReplacementString());
- selectedOptionKey = newSelectedOptionKey;
- }
- }
- currentSuggestion = suggestion;
- setSelectedItemIcon(suggestion.getIconUri());
- }
-
- // Collect captions so we can calculate minimum width for textarea
- if (captions.length() > 0) {
- captions += "|";
- }
- captions += Util.escapeHTML(suggestion.getReplacementString());
- }
-
- if ((!waitingForFilteringResponse || popupOpenerClicked)
- && uidl.hasVariable("selected")
- && uidl.getStringArrayVariable("selected").length == 0) {
- // select nulled
- if (!waitingForFilteringResponse || !popupOpenerClicked) {
- if (!focused) {
- /*
- * client.updateComponent overwrites all styles so we must
- * ALWAYS set the prompting style at this point, even though
- * we think it has been set already...
- */
- prompting = false;
- setPromptingOn();
- } else {
- // we have focus in field, prompting can't be set on,
- // instead just clear the input
- tb.setValue("");
- }
- }
- selectedOptionKey = null;
- }
-
- if (waitingForFilteringResponse
- && lastFilter.toLowerCase().equals(
- uidl.getStringVariable("filter"))) {
- suggestionPopup.showSuggestions(currentSuggestions, currentPage,
- totalMatches);
- waitingForFilteringResponse = false;
- if (!popupOpenerClicked
- && selectPopupItemWhenResponseIsReceived != Select.NONE) {
- // we're paging w/ arrows
- if (selectPopupItemWhenResponseIsReceived == Select.LAST) {
- suggestionPopup.menu.selectLastItem();
- } else {
- suggestionPopup.menu.selectFirstItem();
- }
-
- // This is used for paging so we update the keyboard selection
- // variable as well.
- MenuItem activeMenuItem = suggestionPopup.menu
- .getSelectedItem();
- suggestionPopup.menu.setKeyboardSelectedItem(activeMenuItem);
-
- // Update text field to contain the correct text
- setTextboxText(activeMenuItem.getText());
- tb.setSelectionRange(lastFilter.length(), activeMenuItem
- .getText().length() - lastFilter.length());
-
- selectPopupItemWhenResponseIsReceived = Select.NONE; // reset
- }
- if (updateSelectionWhenReponseIsReceived) {
- suggestionPopup.menu.doPostFilterSelectedItemAction();
- }
- }
-
- // Calculate minumum textarea width
- suggestionPopupMinWidth = minWidth(captions);
-
- popupOpenerClicked = false;
-
- if (!initDone) {
- updateRootWidth();
- }
-
- // Focus dependent style names are lost during the update, so we add
- // them here back again
- if (focused) {
- addStyleDependentName("focus");
- }
-
- initDone = true;
- }
-
- private void updateReadOnly() {
+ protected void updateReadOnly() {
tb.setReadOnly(readonly || !textInputEnabled);
}
- private void setTextInputEnabled(boolean textInputEnabled) {
+ protected void setTextInputEnabled(boolean textInputEnabled) {
// Always update styles as they might have been overwritten
if (textInputEnabled) {
removeStyleDependentName(STYLE_NO_INPUT);
@@ -1251,22 +1048,13 @@ public class VFilterSelect extends Composite implements Paintable, Field,
}
/**
- * Sets the text in the text box using a deferred command if on Gecko. This
- * is required for performance reasons (see #3663).
+ * Sets the text in the text box.
*
* @param text
* the text to set in the text box
*/
- private void setTextboxText(final String text) {
- if (BrowserInfo.get().isFF3()) {
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- tb.setText(text);
- }
- });
- } else {
- tb.setText(text);
- }
+ protected void setTextboxText(final String text) {
+ tb.setText(text);
}
/*
@@ -1289,7 +1077,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
* Turns prompting on. When prompting is turned on a command prompt is shown
* in the text box if nothing has been entered.
*/
- private void setPromptingOn() {
+ protected void setPromptingOn() {
if (!prompting) {
prompting = true;
addStyleDependentName(CLASSNAME_PROMPT);
@@ -1304,7 +1092,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
* @param text
* The text the text box should contain.
*/
- private void setPromptingOff(String text) {
+ protected void setPromptingOff(String text) {
setTextboxText(text);
if (prompting) {
prompting = false;
@@ -1354,7 +1142,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
* @param iconUri
* The URI of the icon
*/
- private void setSelectedItemIcon(String iconUri) {
+ protected void setSelectedItemIcon(String iconUri) {
if (iconUri == null || iconUri == "") {
panel.remove(selectedItemIcon);
updateRootWidth();
@@ -1373,13 +1161,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
private void updateSelectedIconPosition() {
// Position icon vertically to middle
int availableHeight = 0;
- if (BrowserInfo.get().isIE6()) {
- getElement().getStyle().setOverflow(Overflow.HIDDEN);
- availableHeight = getOffsetHeight();
- getElement().getStyle().setProperty("overflow", "");
- } else {
- availableHeight = getOffsetHeight();
- }
+ availableHeight = getOffsetHeight();
int iconHeight = Util.getRequiredHeight(selectedItemIcon);
int marginTop = (availableHeight - iconHeight) / 2;
@@ -1635,7 +1417,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
/**
* Calculate minimum width for FilterSelect textarea
*/
- private native int minWidth(String captions)
+ protected native int minWidth(String captions)
/*-{
if(!captions || captions.length <= 0)
return 0;
@@ -1687,7 +1469,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
}
addStyleDependentName("focus");
- if (client.hasEventListeners(this, EventId.FOCUS)) {
+ if (client.hasWidgetEventListeners(this, EventId.FOCUS)) {
client.updateVariable(paintableId, EventId.FOCUS, "", true);
}
}
@@ -1752,7 +1534,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
}
removeStyleDependentName("focus");
- if (client.hasEventListeners(this, EventId.BLUR)) {
+ if (client.hasWidgetEventListeners(this, EventId.BLUR)) {
client.updateVariable(paintableId, EventId.BLUR, "", true);
}
}
@@ -1783,16 +1565,8 @@ public class VFilterSelect extends Composite implements Paintable, Field,
this.width = width;
}
- if (BrowserInfo.get().isIE6()) {
- // Required in IE when textfield is wider than this.width
- getElement().getStyle().setOverflow(Overflow.HIDDEN);
- horizPaddingAndBorder = Util.setWidthExcludingPaddingAndBorder(
- this, width, horizPaddingAndBorder);
- getElement().getStyle().setProperty("overflow", "");
- } else {
- horizPaddingAndBorder = Util.setWidthExcludingPaddingAndBorder(
- this, width, horizPaddingAndBorder);
- }
+ horizPaddingAndBorder = Util.setWidthExcludingPaddingAndBorder(this,
+ width, horizPaddingAndBorder);
if (initDone) {
updateRootWidth();
@@ -1814,7 +1588,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
* Calculates the width of the select if the select has undefined width.
* Should be called when the width changes or when the icon changes.
*/
- private void updateRootWidth() {
+ protected void updateRootWidth() {
if (width == null) {
/*
* When the width is not specified we must specify width for root
@@ -1882,16 +1656,7 @@ public class VFilterSelect extends Composite implements Paintable, Field,
* @return The width in pixels
*/
private int getMainWidth() {
- int componentWidth;
- if (BrowserInfo.get().isIE6()) {
- // Required in IE when textfield is wider than this.width
- getElement().getStyle().setOverflow(Overflow.HIDDEN);
- componentWidth = getOffsetWidth();
- getElement().getStyle().setProperty("overflow", "");
- } else {
- componentWidth = getOffsetWidth();
- }
- return componentWidth;
+ return getOffsetWidth();
}
/**
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelectPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelectPaintable.java
new file mode 100644
index 0000000000..3249ea17d5
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelectPaintable.java
@@ -0,0 +1,244 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.ui.VFilterSelect.FilterSelectSuggestion;
+
+public class VFilterSelectPaintable extends VAbstractPaintableWidget {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
+ * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
+ */
+ @SuppressWarnings("deprecation")
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Save details
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getId();
+
+ getWidgetForPaintable().readonly = uidl.hasAttribute("readonly");
+ getWidgetForPaintable().enabled = !uidl.hasAttribute("disabled");
+
+ getWidgetForPaintable().tb.setEnabled(getWidgetForPaintable().enabled);
+ getWidgetForPaintable().updateReadOnly();
+
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ // Inverse logic here to make the default case (text input enabled)
+ // work without additional UIDL messages
+ boolean noTextInput = uidl
+ .hasAttribute(VFilterSelect.ATTR_NO_TEXT_INPUT)
+ && uidl.getBooleanAttribute(VFilterSelect.ATTR_NO_TEXT_INPUT);
+ getWidgetForPaintable().setTextInputEnabled(!noTextInput);
+
+ // not a FocusWidget -> needs own tabindex handling
+ if (uidl.hasAttribute("tabindex")) {
+ getWidgetForPaintable().tb.setTabIndex(uidl
+ .getIntAttribute("tabindex"));
+ }
+
+ if (uidl.hasAttribute("filteringmode")) {
+ getWidgetForPaintable().filteringmode = uidl
+ .getIntAttribute("filteringmode");
+ }
+
+ getWidgetForPaintable().immediate = uidl.hasAttribute("immediate");
+
+ getWidgetForPaintable().nullSelectionAllowed = uidl
+ .hasAttribute("nullselect");
+
+ getWidgetForPaintable().nullSelectItem = uidl
+ .hasAttribute("nullselectitem")
+ && uidl.getBooleanAttribute("nullselectitem");
+
+ getWidgetForPaintable().currentPage = uidl.getIntVariable("page");
+
+ if (uidl.hasAttribute("pagelength")) {
+ getWidgetForPaintable().pageLength = uidl
+ .getIntAttribute("pagelength");
+ }
+
+ if (uidl.hasAttribute(VFilterSelect.ATTR_INPUTPROMPT)) {
+ // input prompt changed from server
+ getWidgetForPaintable().inputPrompt = uidl
+ .getStringAttribute(VFilterSelect.ATTR_INPUTPROMPT);
+ } else {
+ getWidgetForPaintable().inputPrompt = "";
+ }
+
+ getWidgetForPaintable().suggestionPopup.updateStyleNames(uidl);
+
+ getWidgetForPaintable().allowNewItem = uidl
+ .hasAttribute("allownewitem");
+ getWidgetForPaintable().lastNewItemString = null;
+
+ getWidgetForPaintable().currentSuggestions.clear();
+ if (!getWidgetForPaintable().waitingForFilteringResponse) {
+ /*
+ * Clear the current suggestions as the server response always
+ * includes the new ones. Exception is when filtering, then we need
+ * to retain the value if the user does not select any of the
+ * options matching the filter.
+ */
+ getWidgetForPaintable().currentSuggestion = null;
+ /*
+ * Also ensure no old items in menu. Unless cleared the old values
+ * may cause odd effects on blur events. Suggestions in menu might
+ * not necessary exist in select at all anymore.
+ */
+ getWidgetForPaintable().suggestionPopup.menu.clearItems();
+
+ }
+
+ final UIDL options = uidl.getChildUIDL(0);
+ if (uidl.hasAttribute("totalMatches")) {
+ getWidgetForPaintable().totalMatches = uidl
+ .getIntAttribute("totalMatches");
+ } else {
+ getWidgetForPaintable().totalMatches = 0;
+ }
+
+ // used only to calculate minimum popup width
+ String captions = Util.escapeHTML(getWidgetForPaintable().inputPrompt);
+
+ for (final Iterator<?> i = options.getChildIterator(); i.hasNext();) {
+ final UIDL optionUidl = (UIDL) i.next();
+ final FilterSelectSuggestion suggestion = getWidgetForPaintable().new FilterSelectSuggestion(
+ optionUidl);
+ getWidgetForPaintable().currentSuggestions.add(suggestion);
+ if (optionUidl.hasAttribute("selected")) {
+ if (!getWidgetForPaintable().waitingForFilteringResponse
+ || getWidgetForPaintable().popupOpenerClicked) {
+ String newSelectedOptionKey = Integer.toString(suggestion
+ .getOptionKey());
+ if (!newSelectedOptionKey
+ .equals(getWidgetForPaintable().selectedOptionKey)
+ || suggestion.getReplacementString().equals(
+ getWidgetForPaintable().tb.getText())) {
+ // Update text field if we've got a new selection
+ // Also update if we've got the same text to retain old
+ // text selection behavior
+ getWidgetForPaintable().setPromptingOff(
+ suggestion.getReplacementString());
+ getWidgetForPaintable().selectedOptionKey = newSelectedOptionKey;
+ }
+ }
+ getWidgetForPaintable().currentSuggestion = suggestion;
+ getWidgetForPaintable().setSelectedItemIcon(
+ suggestion.getIconUri());
+ }
+
+ // Collect captions so we can calculate minimum width for textarea
+ if (captions.length() > 0) {
+ captions += "|";
+ }
+ captions += Util.escapeHTML(suggestion.getReplacementString());
+ }
+
+ if ((!getWidgetForPaintable().waitingForFilteringResponse || getWidgetForPaintable().popupOpenerClicked)
+ && uidl.hasVariable("selected")
+ && uidl.getStringArrayVariable("selected").length == 0) {
+ // select nulled
+ if (!getWidgetForPaintable().waitingForFilteringResponse
+ || !getWidgetForPaintable().popupOpenerClicked) {
+ if (!getWidgetForPaintable().focused) {
+ /*
+ * client.updateComponent overwrites all styles so we must
+ * ALWAYS set the prompting style at this point, even though
+ * we think it has been set already...
+ */
+ getWidgetForPaintable().prompting = false;
+ getWidgetForPaintable().setPromptingOn();
+ } else {
+ // we have focus in field, prompting can't be set on,
+ // instead just clear the input
+ getWidgetForPaintable().tb.setValue("");
+ }
+ }
+ getWidgetForPaintable().selectedOptionKey = null;
+ }
+
+ if (getWidgetForPaintable().waitingForFilteringResponse
+ && getWidgetForPaintable().lastFilter.toLowerCase().equals(
+ uidl.getStringVariable("filter"))) {
+ getWidgetForPaintable().suggestionPopup.showSuggestions(
+ getWidgetForPaintable().currentSuggestions,
+ getWidgetForPaintable().currentPage,
+ getWidgetForPaintable().totalMatches);
+ getWidgetForPaintable().waitingForFilteringResponse = false;
+ if (!getWidgetForPaintable().popupOpenerClicked
+ && getWidgetForPaintable().selectPopupItemWhenResponseIsReceived != VFilterSelect.Select.NONE) {
+ // we're paging w/ arrows
+ if (getWidgetForPaintable().selectPopupItemWhenResponseIsReceived == VFilterSelect.Select.LAST) {
+ getWidgetForPaintable().suggestionPopup.menu
+ .selectLastItem();
+ } else {
+ getWidgetForPaintable().suggestionPopup.menu
+ .selectFirstItem();
+ }
+
+ // This is used for paging so we update the keyboard selection
+ // variable as well.
+ MenuItem activeMenuItem = getWidgetForPaintable().suggestionPopup.menu
+ .getSelectedItem();
+ getWidgetForPaintable().suggestionPopup.menu
+ .setKeyboardSelectedItem(activeMenuItem);
+
+ // Update text field to contain the correct text
+ getWidgetForPaintable()
+ .setTextboxText(activeMenuItem.getText());
+ getWidgetForPaintable().tb.setSelectionRange(
+ getWidgetForPaintable().lastFilter.length(),
+ activeMenuItem.getText().length()
+ - getWidgetForPaintable().lastFilter.length());
+
+ getWidgetForPaintable().selectPopupItemWhenResponseIsReceived = VFilterSelect.Select.NONE; // reset
+ }
+ if (getWidgetForPaintable().updateSelectionWhenReponseIsReceived) {
+ getWidgetForPaintable().suggestionPopup.menu
+ .doPostFilterSelectedItemAction();
+ }
+ }
+
+ // Calculate minumum textarea width
+ getWidgetForPaintable().suggestionPopupMinWidth = getWidgetForPaintable()
+ .minWidth(captions);
+
+ getWidgetForPaintable().popupOpenerClicked = false;
+
+ if (!getWidgetForPaintable().initDone) {
+ getWidgetForPaintable().updateRootWidth();
+ }
+
+ // Focus dependent style names are lost during the update, so we add
+ // them here back again
+ if (getWidgetForPaintable().focused) {
+ getWidgetForPaintable().addStyleDependentName("focus");
+ }
+
+ getWidgetForPaintable().initDone = true;
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VFilterSelect.class);
+ }
+
+ @Override
+ public VFilterSelect getWidgetForPaintable() {
+ return (VFilterSelect) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VForm.java b/src/com/vaadin/terminal/gwt/client/ui/VForm.java
index c0a6e5b275..d70d7ed0d8 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VForm.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VForm.java
@@ -16,12 +16,9 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation;
import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.VErrorMessage;
@@ -36,33 +33,33 @@ public class VForm extends ComplexPanel implements Container, KeyDownHandler {
public static final String CLASSNAME = "v-form";
- private Container lo;
- private Element legend = DOM.createLegend();
- private Element caption = DOM.createSpan();
+ Widget lo;
+ Element legend = DOM.createLegend();
+ Element caption = DOM.createSpan();
private Element errorIndicatorElement = DOM.createDiv();
- private Element desc = DOM.createDiv();
- private Icon icon;
- private VErrorMessage errorMessage = new VErrorMessage();
+ Element desc = DOM.createDiv();
+ Icon icon;
+ VErrorMessage errorMessage = new VErrorMessage();
- private Element fieldContainer = DOM.createDiv();
+ Element fieldContainer = DOM.createDiv();
- private Element footerContainer = DOM.createDiv();
+ Element footerContainer = DOM.createDiv();
- private Element fieldSet = DOM.createFieldSet();
+ Element fieldSet = DOM.createFieldSet();
- private Container footer;
+ Widget footer;
- private ApplicationConnection client;
+ ApplicationConnection client;
private RenderInformation renderInformation = new RenderInformation();
private int borderPaddingHorizontal = -1;
- private boolean rendering = false;
+ boolean rendering = false;
ShortcutActionHandler shortcutHandler;
- private HandlerRegistration keyDownRegistration;
+ HandlerRegistration keyDownRegistration;
public VForm() {
setElement(DOM.createDiv());
@@ -84,139 +81,12 @@ public class VForm extends ComplexPanel implements Container, KeyDownHandler {
fieldSet.appendChild(footerContainer);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
- this.client = client;
- id = uidl.getId();
-
- if (client.updateComponent(this, uidl, false)) {
- rendering = false;
- return;
- }
-
- boolean legendEmpty = true;
- if (uidl.hasAttribute("caption")) {
- caption.setInnerText(uidl.getStringAttribute("caption"));
- legendEmpty = false;
- } else {
- caption.setInnerText("");
- }
- if (uidl.hasAttribute("icon")) {
- if (icon == null) {
- icon = new Icon(client);
- legend.insertFirst(icon.getElement());
- }
- icon.setUri(uidl.getStringAttribute("icon"));
- legendEmpty = false;
- } else {
- if (icon != null) {
- legend.removeChild(icon.getElement());
- }
- }
- if (legendEmpty) {
- addStyleDependentName("nocaption");
- } else {
- removeStyleDependentName("nocaption");
- }
-
- if (uidl.hasAttribute("error")) {
- final UIDL errorUidl = uidl.getErrors();
- errorMessage.updateFromUIDL(errorUidl);
- errorMessage.setVisible(true);
-
- } else {
- errorMessage.setVisible(false);
- }
-
- if (uidl.hasAttribute("description")) {
- desc.setInnerHTML(uidl.getStringAttribute("description"));
- if (desc.getParentElement() == null) {
- fieldSet.insertAfter(desc, legend);
- }
- } else {
- desc.setInnerHTML("");
- if (desc.getParentElement() != null) {
- fieldSet.removeChild(desc);
- }
- }
-
- updateSize();
-
- // first render footer so it will be easier to handle relative height of
- // main layout
- if (uidl.getChildCount() > 1
- && !uidl.getChildUIDL(1).getTag().equals("actions")) {
- // render footer
- Container newFooter = (Container) client.getPaintable(uidl
- .getChildUIDL(1));
- if (footer == null) {
- add((Widget) newFooter, footerContainer);
- footer = newFooter;
- } else if (newFooter != footer) {
- remove((Widget) footer);
- client.unregisterPaintable(footer);
- add((Widget) newFooter, footerContainer);
- }
- footer = newFooter;
- footer.updateFromUIDL(uidl.getChildUIDL(1), client);
- // needed for the main layout to know the space it has available
- updateSize();
- } else {
- if (footer != null) {
- remove((Widget) footer);
- client.unregisterPaintable(footer);
- // needed for the main layout to know the space it has available
- updateSize();
- }
- }
-
- final UIDL layoutUidl = uidl.getChildUIDL(0);
- Container newLo = (Container) client.getPaintable(layoutUidl);
- if (lo == null) {
- lo = newLo;
- add((Widget) lo, fieldContainer);
- } else if (lo != newLo) {
- client.unregisterPaintable(lo);
- remove((Widget) lo);
- lo = newLo;
- add((Widget) lo, fieldContainer);
- }
- lo.updateFromUIDL(layoutUidl, client);
-
- // also recalculates size of the footer if undefined size form - see
- // #3710
- updateSize();
- client.runDescendentsLayout(this);
-
- // We may have actions attached
- if (uidl.getChildCount() > 1) {
- UIDL childUidl = uidl.getChildByTagName("actions");
- if (childUidl != null) {
- if (shortcutHandler == null) {
- shortcutHandler = new ShortcutActionHandler(id, client);
- keyDownRegistration = addDomHandler(this,
- KeyDownEvent.getType());
- }
- shortcutHandler.updateActionMap(childUidl);
- }
- } else if (shortcutHandler != null) {
- keyDownRegistration.removeHandler();
- shortcutHandler = null;
- keyDownRegistration = null;
- }
-
- rendering = false;
- }
-
public void updateSize() {
renderInformation.updateSize(getElement());
renderInformation.setContentAreaHeight(renderInformation
.getRenderedSize().getHeight() - getSpaceConsumedVertically());
- if (BrowserInfo.get().isIE6()) {
- getElement().getStyle().setProperty("overflow", "hidden");
- }
renderInformation.setContentAreaWidth(renderInformation
.getRenderedSize().getWidth() - borderPaddingHorizontal);
}
@@ -244,16 +114,16 @@ public class VForm extends ComplexPanel implements Container, KeyDownHandler {
}
remove(oldComponent);
if (oldComponent == lo) {
- lo = (Container) newComponent;
- add((Widget) lo, fieldContainer);
+ lo = newComponent;
+ add(newComponent, fieldContainer);
} else {
- footer = (Container) newComponent;
- add((Widget) footer, footerContainer);
+ footer = newComponent;
+ add(newComponent, footerContainer);
}
}
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> child) {
if (height != null && !"".equals(height) && width != null
&& !"".equals(width)) {
@@ -273,11 +143,6 @@ public class VForm extends ComplexPanel implements Container, KeyDownHandler {
}
- public void updateCaption(Paintable component, UIDL uidl) {
- // NOP form don't render caption for neither field layout nor footer
- // layout
- }
-
@Override
public void setHeight(String height) {
if (this.height.equals(height)) {
@@ -321,11 +186,23 @@ public class VForm extends ComplexPanel implements Container, KeyDownHandler {
if (!rendering && height.equals("")) {
// Width might affect height
- Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
+ Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this,
+ this);
}
}
public void onKeyDown(KeyDownEvent event) {
shortcutHandler.handleKeyboardEvent(Event.as(event.getNativeEvent()));
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
+ @Override
+ protected void add(Widget child, Element container) {
+ // Overridden to allow VFormPaintable to call this. Should be removed
+ // once functionality from VFormPaintable is moved to VForm.
+ super.add(child, container);
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java
index 174e66b7aa..b2357f11e1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java
@@ -23,11 +23,12 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.StyleConstants;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.VTooltip;
/**
@@ -37,13 +38,13 @@ public class VFormLayout extends SimplePanel implements Container {
private final static String CLASSNAME = "v-formlayout";
- private ApplicationConnection client;
- private VFormLayoutTable table;
+ ApplicationConnection client;
+ VFormLayoutTable table;
private String width = "";
private String height = "";
- private boolean rendering = false;
+ boolean rendering = false;
public VFormLayout() {
super();
@@ -81,8 +82,8 @@ public class VFormLayout extends SimplePanel implements Container {
private static final int COLUMN_ERRORFLAG = 1;
private static final int COLUMN_WIDGET = 2;
- private HashMap<Paintable, Caption> componentToCaption = new HashMap<Paintable, Caption>();
- private HashMap<Paintable, ErrorFlag> componentToError = new HashMap<Paintable, ErrorFlag>();
+ private HashMap<Widget, Caption> widgetToCaption = new HashMap<Widget, Caption>();
+ private HashMap<Widget, ErrorFlag> widgetToError = new HashMap<Widget, ErrorFlag>();
public VFormLayoutTable() {
DOM.setElementProperty(getElement(), "cellPadding", "0");
@@ -111,26 +112,30 @@ public class VFormLayout extends SimplePanel implements Container {
for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext(); i++) {
prepareCell(i, 1);
final UIDL childUidl = (UIDL) it.next();
- final Paintable p = client.getPaintable(childUidl);
- Caption caption = componentToCaption.get(p);
+ final VPaintableWidget childPaintable = client
+ .getPaintable(childUidl);
+ Widget childWidget = childPaintable.getWidgetForPaintable();
+ Caption caption = widgetToCaption.get(childWidget);
if (caption == null) {
- caption = new Caption(p, client);
+ caption = new Caption(childPaintable, client);
caption.addClickHandler(this);
- componentToCaption.put(p, caption);
+ widgetToCaption.put(childWidget, caption);
}
- ErrorFlag error = componentToError.get(p);
+ ErrorFlag error = widgetToError.get(childWidget);
if (error == null) {
error = new ErrorFlag();
- componentToError.put(p, error);
+ widgetToError.put(childWidget, error);
}
prepareCell(i, COLUMN_WIDGET);
- final Paintable oldComponent = (Paintable) getWidget(i,
- COLUMN_WIDGET);
- if (oldComponent == null) {
- setWidget(i, COLUMN_WIDGET, (Widget) p);
- } else if (oldComponent != p) {
- client.unregisterPaintable(oldComponent);
- setWidget(i, COLUMN_WIDGET, (Widget) p);
+
+ Widget oldWidget = getWidget(i, COLUMN_WIDGET);
+ if (oldWidget == null) {
+ setWidget(i, COLUMN_WIDGET, childWidget);
+ } else if (oldWidget != childWidget) {
+ final VPaintableWidget oldPaintable = VPaintableMap.get(
+ client).getPaintable(oldWidget);
+ client.unregisterPaintable(oldPaintable);
+ setWidget(i, COLUMN_WIDGET, childWidget);
}
getCellFormatter().setStyleName(i, COLUMN_WIDGET,
CLASSNAME + "-contentcell");
@@ -144,7 +149,7 @@ public class VFormLayout extends SimplePanel implements Container {
CLASSNAME + "-errorcell");
setWidget(i, COLUMN_ERRORFLAG, error);
- p.updateFromUIDL(childUidl, client);
+ childPaintable.updateFromUIDL(childUidl, client);
String rowstyles = CLASSNAME + "-row";
if (i == 0) {
@@ -159,9 +164,11 @@ public class VFormLayout extends SimplePanel implements Container {
}
while (getRowCount() > i) {
- final Paintable p = (Paintable) getWidget(i, COLUMN_WIDGET);
+ Widget w = getWidget(i, COLUMN_WIDGET);
+ final VPaintableWidget p = VPaintableMap.get(client)
+ .getPaintable(w);
client.unregisterPaintable(p);
- componentToCaption.remove(p);
+ widgetToCaption.remove(w);
removeRow(i);
}
@@ -169,8 +176,8 @@ public class VFormLayout extends SimplePanel implements Container {
* Must update relative sized fields last when it is clear how much
* space they are allowed to use
*/
- for (Paintable p : componentToCaption.keySet()) {
- client.handleComponentRelativeSize((Widget) p);
+ for (Widget p : widgetToCaption.keySet()) {
+ client.handleComponentRelativeSize(p);
}
}
@@ -194,16 +201,20 @@ public class VFormLayout extends SimplePanel implements Container {
for (i = 0; i < getRowCount(); i++) {
Widget candidate = getWidget(i, COLUMN_WIDGET);
if (oldComponent == candidate) {
- Caption oldCap = componentToCaption.get(oldComponent);
- final Caption newCap = new Caption(
- (Paintable) newComponent, client);
+ VPaintableMap paintableMap = VPaintableMap.get(client);
+ VPaintableWidget oldPaintable = paintableMap
+ .getPaintable(oldComponent);
+ VPaintableWidget newPaintable = paintableMap
+ .getPaintable(newComponent);
+ Caption oldCap = widgetToCaption.get(oldComponent);
+ final Caption newCap = new Caption(newPaintable, client);
newCap.addClickHandler(this);
newCap.setStyleName(oldCap.getStyleName());
- componentToCaption.put((Paintable) newComponent, newCap);
- ErrorFlag error = componentToError.get(newComponent);
+ widgetToCaption.put(newComponent, newCap);
+ ErrorFlag error = widgetToError.get(newComponent);
if (error == null) {
error = new ErrorFlag();
- componentToError.put((Paintable) newComponent, error);
+ widgetToError.put(newComponent, error);
}
setWidget(i, COLUMN_CAPTION, newCap);
@@ -216,24 +227,26 @@ public class VFormLayout extends SimplePanel implements Container {
}
public boolean hasChildComponent(Widget component) {
- return componentToCaption.containsKey(component);
+ return widgetToCaption.containsKey(component);
}
- public void updateCaption(Paintable component, UIDL uidl) {
- final Caption c = componentToCaption.get(component);
+ public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
+ final Caption c = widgetToCaption.get(paintable
+ .getWidgetForPaintable());
if (c != null) {
c.updateCaption(uidl);
}
- final ErrorFlag e = componentToError.get(component);
+ final ErrorFlag e = widgetToError.get(paintable
+ .getWidgetForPaintable());
if (e != null) {
- e.updateFromUIDL(uidl, component);
+ e.updateFromUIDL(uidl, paintable);
}
}
public int getAllocatedWidth(Widget child, int availableWidth) {
- Caption caption = componentToCaption.get(child);
- ErrorFlag error = componentToError.get(child);
+ Caption caption = widgetToCaption.get(child);
+ ErrorFlag error = widgetToError.get(child);
int width = availableWidth;
if (caption != null) {
@@ -266,21 +279,6 @@ public class VFormLayout extends SimplePanel implements Container {
}
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
-
- this.client = client;
-
- if (client.updateComponent(this, uidl, true)) {
- rendering = false;
- return;
- }
-
- table.updateFromUIDL(uidl, client);
-
- rendering = false;
- }
-
public boolean isDynamicWidth() {
return width.equals("");
}
@@ -293,15 +291,11 @@ public class VFormLayout extends SimplePanel implements Container {
table.replaceChildComponent(oldComponent, newComponent);
}
- public void updateCaption(Paintable component, UIDL uidl) {
- table.updateCaption(component, uidl);
- }
-
public class Caption extends HTML {
public static final String CLASSNAME = "v-caption";
- private final Paintable owner;
+ private final VPaintableWidget owner;
private Element requiredFieldIndicator;
@@ -318,7 +312,7 @@ public class VFormLayout extends SimplePanel implements Container {
* return null
* @param client
*/
- public Caption(Paintable component, ApplicationConnection client) {
+ public Caption(VPaintableWidget component, ApplicationConnection client) {
super();
this.client = client;
owner = component;
@@ -411,6 +405,7 @@ public class VFormLayout extends SimplePanel implements Container {
// Workaround for IE weirdness, sometimes returns bad height in some
// circumstances when Caption is empty. See #1444
// IE7 bugs more often. I wonder what happens when IE8 arrives...
+ // FIXME: This could be unnecessary for IE8+
if (BrowserInfo.get().isIE()) {
if (isEmpty) {
setHeight("0px");
@@ -429,7 +424,7 @@ public class VFormLayout extends SimplePanel implements Container {
*
* @return owner Widget
*/
- public Paintable getOwner() {
+ public VPaintableWidget getOwner() {
return owner;
}
@@ -446,14 +441,14 @@ public class VFormLayout extends SimplePanel implements Container {
private static final String CLASSNAME = VFormLayout.CLASSNAME
+ "-error-indicator";
Element errorIndicatorElement;
- private Paintable owner;
+ private VPaintableWidget owner;
public ErrorFlag() {
setStyleName(CLASSNAME);
sinkEvents(VTooltip.TOOLTIP_EVENTS);
}
- public void updateFromUIDL(UIDL uidl, Paintable component) {
+ public void updateFromUIDL(UIDL uidl, VPaintableWidget component) {
owner = component;
if (uidl.hasAttribute("error")
&& !uidl.getBooleanAttribute("hideErrors")) {
@@ -481,7 +476,7 @@ public class VFormLayout extends SimplePanel implements Container {
}
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
if (height.equals("") || width.equals("")) {
// A dynamic size might change due to children changes
return false;
@@ -525,9 +520,14 @@ public class VFormLayout extends SimplePanel implements Container {
table.setContentWidths();
if (height.equals("")) {
// Width might affect height
- Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
+ Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this,
+ this);
}
}
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFormLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VFormLayoutPaintable.java
new file mode 100644
index 0000000000..1efdcfc722
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VFormLayoutPaintable.java
@@ -0,0 +1,39 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VFormLayoutPaintable extends VAbstractPaintableWidgetContainer {
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+
+ getWidgetForPaintable().client = client;
+
+ if (client.updateComponent(this, uidl, true)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ getWidgetForPaintable().table.updateFromUIDL(uidl, client);
+
+ getWidgetForPaintable().rendering = false;
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ getWidgetForPaintable().table.updateCaption(component, uidl);
+ }
+
+ @Override
+ public VFormLayout getWidgetForPaintable() {
+ return (VFormLayout) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VFormLayout.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFormPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VFormPaintable.java
new file mode 100644
index 0000000000..4b59d64a71
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VFormPaintable.java
@@ -0,0 +1,173 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VFormPaintable extends VAbstractPaintableWidgetContainer {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().id = uidl.getId();
+
+ if (client.updateComponent(this, uidl, false)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ boolean legendEmpty = true;
+ if (uidl.hasAttribute("caption")) {
+ getWidgetForPaintable().caption.setInnerText(uidl
+ .getStringAttribute("caption"));
+ legendEmpty = false;
+ } else {
+ getWidgetForPaintable().caption.setInnerText("");
+ }
+ if (uidl.hasAttribute("icon")) {
+ if (getWidgetForPaintable().icon == null) {
+ getWidgetForPaintable().icon = new Icon(client);
+ getWidgetForPaintable().legend
+ .insertFirst(getWidgetForPaintable().icon.getElement());
+ }
+ getWidgetForPaintable().icon
+ .setUri(uidl.getStringAttribute("icon"));
+ legendEmpty = false;
+ } else {
+ if (getWidgetForPaintable().icon != null) {
+ getWidgetForPaintable().legend
+ .removeChild(getWidgetForPaintable().icon.getElement());
+ }
+ }
+ if (legendEmpty) {
+ getWidgetForPaintable().addStyleDependentName("nocaption");
+ } else {
+ getWidgetForPaintable().removeStyleDependentName("nocaption");
+ }
+
+ if (uidl.hasAttribute("error")) {
+ final UIDL errorUidl = uidl.getErrors();
+ getWidgetForPaintable().errorMessage.updateFromUIDL(errorUidl);
+ getWidgetForPaintable().errorMessage.setVisible(true);
+ } else {
+ getWidgetForPaintable().errorMessage.setVisible(false);
+ }
+
+ if (uidl.hasAttribute("description")) {
+ getWidgetForPaintable().desc.setInnerHTML(uidl
+ .getStringAttribute("description"));
+ if (getWidgetForPaintable().desc.getParentElement() == null) {
+ getWidgetForPaintable().fieldSet.insertAfter(
+ getWidgetForPaintable().desc,
+ getWidgetForPaintable().legend);
+ }
+ } else {
+ getWidgetForPaintable().desc.setInnerHTML("");
+ if (getWidgetForPaintable().desc.getParentElement() != null) {
+ getWidgetForPaintable().fieldSet
+ .removeChild(getWidgetForPaintable().desc);
+ }
+ }
+
+ getWidgetForPaintable().updateSize();
+
+ // first render footer so it will be easier to handle relative height of
+ // main layout
+ if (uidl.getChildCount() > 1
+ && !uidl.getChildUIDL(1).getTag().equals("actions")) {
+ // render footer
+ VPaintableWidget newFooter = client.getPaintable(uidl
+ .getChildUIDL(1));
+ Widget newFooterWidget = newFooter.getWidgetForPaintable();
+ if (getWidgetForPaintable().footer == null) {
+ getWidgetForPaintable().add(newFooter.getWidgetForPaintable(),
+ getWidgetForPaintable().footerContainer);
+ getWidgetForPaintable().footer = newFooterWidget;
+ } else if (newFooter != getWidgetForPaintable().footer) {
+ getWidgetForPaintable().remove(getWidgetForPaintable().footer);
+ client.unregisterPaintable(VPaintableMap.get(getConnection())
+ .getPaintable(getWidgetForPaintable().footer));
+ getWidgetForPaintable().add(newFooter.getWidgetForPaintable(),
+ getWidgetForPaintable().footerContainer);
+ }
+ getWidgetForPaintable().footer = newFooterWidget;
+ newFooter.updateFromUIDL(uidl.getChildUIDL(1), client);
+ // needed for the main layout to know the space it has available
+ getWidgetForPaintable().updateSize();
+ } else {
+ if (getWidgetForPaintable().footer != null) {
+ getWidgetForPaintable().remove(getWidgetForPaintable().footer);
+ client.unregisterPaintable(VPaintableMap.get(getConnection())
+ .getPaintable(getWidgetForPaintable().footer));
+ // needed for the main layout to know the space it has available
+ getWidgetForPaintable().updateSize();
+ }
+ }
+
+ final UIDL layoutUidl = uidl.getChildUIDL(0);
+ VPaintableWidget newLayout = client.getPaintable(layoutUidl);
+ Widget newLayoutWidget = newLayout.getWidgetForPaintable();
+ if (getWidgetForPaintable().lo == null) {
+ // Layout not rendered before
+ getWidgetForPaintable().lo = newLayoutWidget;
+ getWidgetForPaintable().add(newLayoutWidget,
+ getWidgetForPaintable().fieldContainer);
+ } else if (getWidgetForPaintable().lo != newLayoutWidget) {
+ // Layout has changed
+ client.unregisterPaintable(VPaintableMap.get(getConnection())
+ .getPaintable(getWidgetForPaintable().lo));
+ getWidgetForPaintable().remove(getWidgetForPaintable().lo);
+ getWidgetForPaintable().lo = newLayoutWidget;
+ getWidgetForPaintable().add(newLayoutWidget,
+ getWidgetForPaintable().fieldContainer);
+ }
+ newLayout.updateFromUIDL(layoutUidl, client);
+
+ // also recalculates size of the footer if undefined size form - see
+ // #3710
+ getWidgetForPaintable().updateSize();
+ client.runDescendentsLayout(getWidgetForPaintable());
+
+ // We may have actions attached
+ if (uidl.getChildCount() > 1) {
+ UIDL childUidl = uidl.getChildByTagName("actions");
+ if (childUidl != null) {
+ if (getWidgetForPaintable().shortcutHandler == null) {
+ getWidgetForPaintable().shortcutHandler = new ShortcutActionHandler(
+ getId(), client);
+ getWidgetForPaintable().keyDownRegistration = getWidgetForPaintable()
+ .addDomHandler(getWidgetForPaintable(),
+ KeyDownEvent.getType());
+ }
+ getWidgetForPaintable().shortcutHandler
+ .updateActionMap(childUidl);
+ }
+ } else if (getWidgetForPaintable().shortcutHandler != null) {
+ getWidgetForPaintable().keyDownRegistration.removeHandler();
+ getWidgetForPaintable().shortcutHandler = null;
+ getWidgetForPaintable().keyDownRegistration = null;
+ }
+
+ getWidgetForPaintable().rendering = false;
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ // NOP form don't render caption for neither field layout nor footer
+ // layout
+ }
+
+ @Override
+ public VForm getWidgetForPaintable() {
+ return (VForm) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VForm.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
index 82b3eabf40..e6e167f077 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
@@ -14,76 +14,58 @@ import java.util.Set;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
-import com.google.gwt.event.dom.client.DomEvent.Type;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.StyleConstants;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
-public class VGridLayout extends SimplePanel implements Paintable, Container {
+public class VGridLayout extends SimplePanel implements Container {
public static final String CLASSNAME = "v-gridlayout";
private DivElement margin = Document.get().createDivElement();
- private final AbsolutePanel canvas = new AbsolutePanel();
+ final AbsolutePanel canvas = new AbsolutePanel();
- private ApplicationConnection client;
+ ApplicationConnection client;
protected HashMap<Widget, ChildComponentContainer> widgetToComponentContainer = new HashMap<Widget, ChildComponentContainer>();
- private HashMap<Paintable, Cell> paintableToCell = new HashMap<Paintable, Cell>();
+ HashMap<Widget, Cell> widgetToCell = new HashMap<Widget, Cell>();
private int spacingPixelsHorizontal;
private int spacingPixelsVertical;
- private int[] columnWidths;
- private int[] rowHeights;
+ int[] columnWidths;
+ int[] rowHeights;
private String height;
private String width;
- private int[] colExpandRatioArray;
+ int[] colExpandRatioArray;
- private int[] rowExpandRatioArray;
+ int[] rowExpandRatioArray;
- private int[] minColumnWidths;
+ int[] minColumnWidths;
private int[] minRowHeights;
- private boolean rendering;
+ boolean rendering;
- private HashMap<Widget, ChildComponentContainer> nonRenderedWidgets;
+ HashMap<Widget, ChildComponentContainer> nonRenderedWidgets;
- private boolean sizeChangedDuringRendering = false;
-
- private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
- this, EventId.LAYOUT_CLICK) {
-
- @Override
- protected Paintable getChildComponent(Element element) {
- return getComponent(element);
- }
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
- };
+ boolean sizeChangedDuringRendering = false;
public VGridLayout() {
super();
@@ -133,125 +115,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
return spacingPixelsVertical;
}
- @SuppressWarnings("unchecked")
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
- this.client = client;
-
- if (client.updateComponent(this, uidl, true)) {
- rendering = false;
- return;
- }
- clickEventHandler.handleEventHandlerRegistration(client);
-
- canvas.setWidth("0px");
-
- handleMargins(uidl);
- detectSpacing(uidl);
-
- int cols = uidl.getIntAttribute("w");
- int rows = uidl.getIntAttribute("h");
-
- columnWidths = new int[cols];
- rowHeights = new int[rows];
-
- if (cells == null) {
- cells = new Cell[cols][rows];
- } else if (cells.length != cols || cells[0].length != rows) {
- Cell[][] newCells = new Cell[cols][rows];
- for (int i = 0; i < cells.length; i++) {
- for (int j = 0; j < cells[i].length; j++) {
- if (i < cols && j < rows) {
- newCells[i][j] = cells[i][j];
- }
- }
- }
- cells = newCells;
- }
-
- nonRenderedWidgets = (HashMap<Widget, ChildComponentContainer>) widgetToComponentContainer
- .clone();
-
- final int[] alignments = uidl.getIntArrayAttribute("alignments");
- int alignmentIndex = 0;
-
- LinkedList<Cell> pendingCells = new LinkedList<Cell>();
-
- LinkedList<Cell> relativeHeighted = new LinkedList<Cell>();
-
- for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) {
- final UIDL r = (UIDL) i.next();
- if ("gr".equals(r.getTag())) {
- for (final Iterator<?> j = r.getChildIterator(); j.hasNext();) {
- final UIDL c = (UIDL) j.next();
- if ("gc".equals(c.getTag())) {
- Cell cell = getCell(c);
- if (cell.hasContent()) {
- boolean rendered = cell.renderIfNoRelativeWidth();
- cell.alignment = alignments[alignmentIndex++];
- if (!rendered) {
- pendingCells.add(cell);
- }
-
- if (cell.colspan > 1) {
- storeColSpannedCell(cell);
- } else if (rendered) {
- // strore non-colspanned widths to columnWidth
- // array
- if (columnWidths[cell.col] < cell.getWidth()) {
- columnWidths[cell.col] = cell.getWidth();
- }
- }
- if (cell.hasRelativeHeight()) {
- relativeHeighted.add(cell);
- }
- }
- }
- }
- }
- }
-
- colExpandRatioArray = uidl.getIntArrayAttribute("colExpand");
- rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand");
- distributeColSpanWidths();
-
- minColumnWidths = cloneArray(columnWidths);
- expandColumns();
-
- renderRemainingComponentsWithNoRelativeHeight(pendingCells);
-
- detectRowHeights();
-
- expandRows();
-
- renderRemainingComponents(pendingCells);
-
- for (Cell cell : relativeHeighted) {
- // rendering done above so cell.cc should not be null
- Widget widget2 = cell.cc.getWidget();
- client.handleComponentRelativeSize(widget2);
- cell.cc.updateWidgetSize();
- }
-
- layoutCells();
-
- // clean non rendered components
- for (Widget w : nonRenderedWidgets.keySet()) {
- ChildComponentContainer childComponentContainer = widgetToComponentContainer
- .get(w);
- paintableToCell.remove(w);
- widgetToComponentContainer.remove(w);
- childComponentContainer.removeFromParent();
- client.unregisterPaintable((Paintable) w);
- }
- nonRenderedWidgets = null;
-
- rendering = false;
- sizeChangedDuringRendering = false;
-
- }
-
- private static int[] cloneArray(int[] toBeCloned) {
+ static int[] cloneArray(int[] toBeCloned) {
int[] clone = new int[toBeCloned.length];
for (int i = 0; i < clone.length; i++) {
clone[i] = toBeCloned[i] * 1;
@@ -259,7 +123,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
return clone;
}
- private void expandRows() {
+ void expandRows() {
if (!"".equals(height)) {
int usedSpace = minRowHeights[0];
for (int i = 1; i < minRowHeights.length; i++) {
@@ -295,8 +159,8 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
} else {
expandRows();
layoutCells();
- for (Paintable c : paintableToCell.keySet()) {
- client.handleComponentRelativeSize((Widget) c);
+ for (Widget w : widgetToCell.keySet()) {
+ client.handleComponentRelativeSize(w);
}
}
}
@@ -388,8 +252,8 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
layoutCells();
- for (Paintable c : paintableToCell.keySet()) {
- client.handleComponentRelativeSize((Widget) c);
+ for (Widget w : widgetToCell.keySet()) {
+ client.handleComponentRelativeSize(w);
}
if (heightChanged && "".equals(height)) {
Util.notifyParentOfSizeChange(this, false);
@@ -398,7 +262,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
}
- private void expandColumns() {
+ void expandColumns() {
if (!"".equals(width)) {
int usedSpace = minColumnWidths[0];
for (int i = 1; i < minColumnWidths.length; i++) {
@@ -425,7 +289,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
}
- private void layoutCells() {
+ void layoutCells() {
int x = 0;
int y = 0;
for (int i = 0; i < cells.length; i++) {
@@ -467,13 +331,13 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
return "".equals(width);
}
- private void renderRemainingComponents(LinkedList<Cell> pendingCells) {
+ void renderRemainingComponents(LinkedList<Cell> pendingCells) {
for (Cell cell : pendingCells) {
cell.render();
}
}
- private void detectRowHeights() {
+ void detectRowHeights() {
// collect min rowheight from non-rowspanned cells
for (int i = 0; i < cells.length; i++) {
@@ -528,7 +392,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
l.cells.add(cell);
}
- private void renderRemainingComponentsWithNoRelativeHeight(
+ void renderRemainingComponentsWithNoRelativeHeight(
LinkedList<Cell> pendingCells) {
for (Iterator<Cell> iterator = pendingCells.iterator(); iterator
@@ -546,7 +410,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
* Iterates colspanned cells, ensures cols have enough space to accommodate
* them
*/
- private void distributeColSpanWidths() {
+ void distributeColSpanWidths() {
for (SpanList list : colSpans) {
for (Cell cell : list.cells) {
// cells with relative content may return non 0 here if on
@@ -640,7 +504,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
}
- private void storeColSpannedCell(Cell cell) {
+ void storeColSpannedCell(Cell cell) {
SpanList l = null;
for (SpanList list : colSpans) {
if (list.span < cell.colspan) {
@@ -663,7 +527,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
l.cells.add(cell);
}
- private void detectSpacing(UIDL uidl) {
+ void detectSpacing(UIDL uidl) {
DivElement spacingmeter = Document.get().createDivElement();
spacingmeter.setClassName(CLASSNAME + "-" + "spacing-"
+ (uidl.getBooleanAttribute("spacing") ? "on" : "off"));
@@ -675,7 +539,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
canvas.getElement().removeChild(spacingmeter);
}
- private void handleMargins(UIDL uidl) {
+ void handleMargins(UIDL uidl) {
final VMarginInfo margins = new VMarginInfo(
uidl.getIntAttribute("margins"));
@@ -699,7 +563,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
public boolean hasChildComponent(Widget component) {
- return paintableToCell.containsKey(component);
+ return widgetToCell.containsKey(component);
}
public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
@@ -709,30 +573,14 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
return;
}
- componentContainer.setWidget(newComponent);
+ componentContainer.setPaintable(VPaintableMap.get(client).getPaintable(
+ newComponent));
widgetToComponentContainer.put(newComponent, componentContainer);
- paintableToCell.put((Paintable) newComponent,
- paintableToCell.get(oldComponent));
+ widgetToCell.put(newComponent, widgetToCell.get(oldComponent));
}
- public void updateCaption(Paintable component, UIDL uidl) {
- ChildComponentContainer cc = widgetToComponentContainer.get(component);
- if (cc != null) {
- cc.updateCaption(uidl, client);
- }
- if (!rendering) {
- // ensure rel size details are updated
- paintableToCell.get(component).updateRelSizeStatus(uidl);
- /*
- * This was a component-only update and the possible size change
- * must be propagated to the layout
- */
- client.captionSizeUpdated(component);
- }
- }
-
- public boolean requestLayout(final Set<Paintable> changedChildren) {
+ public boolean requestLayout(final Set<Widget> changedChildren) {
boolean needsLayout = false;
boolean reDistributeColSpanWidths = false;
boolean reDistributeRowSpanHeights = false;
@@ -743,9 +591,9 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
ArrayList<Integer> dirtyColumns = new ArrayList<Integer>();
ArrayList<Integer> dirtyRows = new ArrayList<Integer>();
- for (Paintable paintable : changedChildren) {
+ for (Widget widget : changedChildren) {
- Cell cell = paintableToCell.get(paintable);
+ Cell cell = widgetToCell.get(widget);
if (!cell.hasRelativeHeight() || !cell.hasRelativeWidth()) {
// cell sizes will only stay still if only relatively
// sized components
@@ -886,17 +734,17 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
public RenderSpace getAllocatedSpace(Widget child) {
- Cell cell = paintableToCell.get(child);
+ Cell cell = widgetToCell.get(child);
assert cell != null;
return cell.getAllocatedSpace();
}
- private Cell[][] cells;
+ Cell[][] cells;
/**
* Private helper class.
*/
- private class Cell {
+ class Cell {
private boolean relHeight = false;
private boolean relWidth = false;
private boolean widthCanAffectHeight = false;
@@ -994,12 +842,13 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
protected void render() {
assert childUidl != null;
- Paintable paintable = client.getPaintable(childUidl);
+ VPaintableWidget paintable = client.getPaintable(childUidl);
+ Widget w = paintable.getWidgetForPaintable();
assert paintable != null;
- if (cc == null || cc.getWidget() != paintable) {
- if (widgetToComponentContainer.containsKey(paintable)) {
+ if (cc == null || cc.getWidget() != w) {
+ if (widgetToComponentContainer.containsKey(w)) {
// Component moving from one place to another
- cc = widgetToComponentContainer.get(paintable);
+ cc = widgetToComponentContainer.get(w);
cc.setWidth("");
cc.setHeight("");
/*
@@ -1007,23 +856,23 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
* and this layout has been hidden when moving out, see
* #5372
*/
- cc.setWidget((Widget) paintable);
+ cc.setPaintable(paintable);
} else {
// A new component
- cc = new ChildComponentContainer((Widget) paintable,
+ cc = new ChildComponentContainer(paintable,
CellBasedLayout.ORIENTATION_VERTICAL);
- widgetToComponentContainer.put((Widget) paintable, cc);
+ widgetToComponentContainer.put(w, cc);
cc.setWidth("");
canvas.add(cc, 0, 0);
}
- paintableToCell.put(paintable, this);
+ widgetToCell.put(w, this);
}
cc.renderChild(childUidl, client, -1);
if (sizeChangedDuringRendering && Util.isCached(childUidl)) {
client.handleComponentRelativeSize(cc.getWidget());
}
cc.updateWidgetSize();
- nonRenderedWidgets.remove(paintable);
+ nonRenderedWidgets.remove(w);
}
public UIDL getChildUIDL() {
@@ -1062,17 +911,19 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
// canvas later during the render phase
cc = null;
} else if (cc != null
- && cc.getWidget() != client.getPaintable(c)) {
+ && cc.getWidget() != client.getPaintable(c)
+ .getWidgetForPaintable()) {
// content has changed
cc = null;
- Paintable paintable = client.getPaintable(c);
- if (widgetToComponentContainer.containsKey(paintable)) {
+ VPaintableWidget paintable = client.getPaintable(c);
+ Widget w = paintable.getWidgetForPaintable();
+ if (widgetToComponentContainer.containsKey(w)) {
// cc exist for this component (moved) use that for this
// cell
- cc = widgetToComponentContainer.get(paintable);
+ cc = widgetToComponentContainer.get(w);
cc.setWidth("");
cc.setHeight("");
- paintableToCell.put(paintable, this);
+ widgetToCell.put(w, this);
}
}
}
@@ -1102,7 +953,7 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
}
- private Cell getCell(UIDL c) {
+ Cell getCell(UIDL c) {
int row = c.getIntAttribute("y");
int col = c.getIntAttribute("x");
Cell cell = cells[col][row];
@@ -1125,8 +976,12 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
* @return The Paintable which the element is a part of. Null if the element
* belongs to the layout and not to a child.
*/
- private Paintable getComponent(Element element) {
+ VPaintableWidget getComponent(Element element) {
return Util.getPaintableForElement(client, this, element);
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VGridLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VGridLayoutPaintable.java
new file mode 100644
index 0000000000..639ac1f8de
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VGridLayoutPaintable.java
@@ -0,0 +1,193 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.EventId;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.VGridLayout.Cell;
+import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
+
+public class VGridLayoutPaintable extends VAbstractPaintableWidgetContainer {
+ private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
+ this, EventId.LAYOUT_CLICK) {
+
+ @Override
+ protected VPaintableWidget getChildComponent(Element element) {
+ return getWidgetForPaintable().getComponent(element);
+ }
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ };
+
+ @SuppressWarnings("unchecked")
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+ getWidgetForPaintable().client = client;
+
+ if (client.updateComponent(this, uidl, true)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ getWidgetForPaintable().canvas.setWidth("0px");
+
+ getWidgetForPaintable().handleMargins(uidl);
+ getWidgetForPaintable().detectSpacing(uidl);
+
+ int cols = uidl.getIntAttribute("w");
+ int rows = uidl.getIntAttribute("h");
+
+ getWidgetForPaintable().columnWidths = new int[cols];
+ getWidgetForPaintable().rowHeights = new int[rows];
+
+ if (getWidgetForPaintable().cells == null) {
+ getWidgetForPaintable().cells = new Cell[cols][rows];
+ } else if (getWidgetForPaintable().cells.length != cols
+ || getWidgetForPaintable().cells[0].length != rows) {
+ Cell[][] newCells = new Cell[cols][rows];
+ for (int i = 0; i < getWidgetForPaintable().cells.length; i++) {
+ for (int j = 0; j < getWidgetForPaintable().cells[i].length; j++) {
+ if (i < cols && j < rows) {
+ newCells[i][j] = getWidgetForPaintable().cells[i][j];
+ }
+ }
+ }
+ getWidgetForPaintable().cells = newCells;
+ }
+
+ getWidgetForPaintable().nonRenderedWidgets = (HashMap<Widget, ChildComponentContainer>) getWidgetForPaintable().widgetToComponentContainer
+ .clone();
+
+ final int[] alignments = uidl.getIntArrayAttribute("alignments");
+ int alignmentIndex = 0;
+
+ LinkedList<Cell> pendingCells = new LinkedList<Cell>();
+
+ LinkedList<Cell> relativeHeighted = new LinkedList<Cell>();
+
+ for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) {
+ final UIDL r = (UIDL) i.next();
+ if ("gr".equals(r.getTag())) {
+ for (final Iterator<?> j = r.getChildIterator(); j.hasNext();) {
+ final UIDL c = (UIDL) j.next();
+ if ("gc".equals(c.getTag())) {
+ Cell cell = getWidgetForPaintable().getCell(c);
+ if (cell.hasContent()) {
+ boolean rendered = cell.renderIfNoRelativeWidth();
+ cell.alignment = alignments[alignmentIndex++];
+ if (!rendered) {
+ pendingCells.add(cell);
+ }
+
+ if (cell.colspan > 1) {
+ getWidgetForPaintable().storeColSpannedCell(
+ cell);
+ } else if (rendered) {
+ // strore non-colspanned widths to columnWidth
+ // array
+ if (getWidgetForPaintable().columnWidths[cell.col] < cell
+ .getWidth()) {
+ getWidgetForPaintable().columnWidths[cell.col] = cell
+ .getWidth();
+ }
+ }
+ if (cell.hasRelativeHeight()) {
+ relativeHeighted.add(cell);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ getWidgetForPaintable().colExpandRatioArray = uidl
+ .getIntArrayAttribute("colExpand");
+ getWidgetForPaintable().rowExpandRatioArray = uidl
+ .getIntArrayAttribute("rowExpand");
+ getWidgetForPaintable().distributeColSpanWidths();
+
+ getWidgetForPaintable().minColumnWidths = VGridLayout
+ .cloneArray(getWidgetForPaintable().columnWidths);
+ getWidgetForPaintable().expandColumns();
+
+ getWidgetForPaintable().renderRemainingComponentsWithNoRelativeHeight(
+ pendingCells);
+
+ getWidgetForPaintable().detectRowHeights();
+
+ getWidgetForPaintable().expandRows();
+
+ getWidgetForPaintable().renderRemainingComponents(pendingCells);
+
+ for (Cell cell : relativeHeighted) {
+ // rendering done above so cell.cc should not be null
+ Widget widget2 = cell.cc.getWidget();
+ client.handleComponentRelativeSize(widget2);
+ cell.cc.updateWidgetSize();
+ }
+
+ getWidgetForPaintable().layoutCells();
+
+ // clean non rendered components
+ for (Widget w : getWidgetForPaintable().nonRenderedWidgets.keySet()) {
+ ChildComponentContainer childComponentContainer = getWidgetForPaintable().widgetToComponentContainer
+ .get(w);
+ getWidgetForPaintable().widgetToCell.remove(w);
+ getWidgetForPaintable().widgetToComponentContainer.remove(w);
+ childComponentContainer.removeFromParent();
+ VPaintableMap paintableMap = VPaintableMap.get(client);
+ paintableMap.unregisterPaintable(paintableMap.getPaintable(w));
+ }
+ getWidgetForPaintable().nonRenderedWidgets = null;
+
+ getWidgetForPaintable().rendering = false;
+ getWidgetForPaintable().sizeChangedDuringRendering = false;
+
+ }
+
+ public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
+ Widget widget = paintable.getWidgetForPaintable();
+ ChildComponentContainer cc = getWidgetForPaintable().widgetToComponentContainer
+ .get(widget);
+ if (cc != null) {
+ cc.updateCaption(uidl, getConnection());
+ }
+ if (!getWidgetForPaintable().rendering) {
+ // ensure rel size details are updated
+ getWidgetForPaintable().widgetToCell.get(widget)
+ .updateRelSizeStatus(uidl);
+ /*
+ * This was a component-only update and the possible size change
+ * must be propagated to the layout
+ */
+ getConnection().captionSizeUpdated(widget);
+ }
+ }
+
+ @Override
+ public VGridLayout getWidgetForPaintable() {
+ return (VGridLayout) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VGridLayout.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayoutPaintable.java
new file mode 100644
index 0000000000..e5fb4e138b
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayoutPaintable.java
@@ -0,0 +1,17 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+
+public class VHorizontalLayoutPaintable extends VOrderedLayoutPaintable {
+
+ @Override
+ public VHorizontalLayout getWidgetForPaintable() {
+ return (VHorizontalLayout) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected VHorizontalLayout createWidget() {
+ return GWT.create(VHorizontalLayout.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VHorizontalSplitPanelPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VHorizontalSplitPanelPaintable.java
new file mode 100644
index 0000000000..ebc8a5e523
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VHorizontalSplitPanelPaintable.java
@@ -0,0 +1,13 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+
+public class VHorizontalSplitPanelPaintable extends
+ VAbstractSplitPanelPaintable {
+
+ @Override
+ protected VAbstractSplitPanel createWidget() {
+ return GWT.create(VSplitPanelHorizontal.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLabel.java b/src/com/vaadin/terminal/gwt/client/ui/VLabel.java
deleted file mode 100644
index 341e9f3484..0000000000
--- a/src/com/vaadin/terminal/gwt/client/ui/VLabel.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.PreElement;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.HTML;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VTooltip;
-
-public class VLabel extends HTML implements Paintable {
-
- public static final String CLASSNAME = "v-label";
- private static final String CLASSNAME_UNDEFINED_WIDTH = "v-label-undef-w";
-
- private ApplicationConnection client;
- private int verticalPaddingBorder = 0;
- private int horizontalPaddingBorder = 0;
-
- public VLabel() {
- super();
- setStyleName(CLASSNAME);
- sinkEvents(VTooltip.TOOLTIP_EVENTS);
- }
-
- public VLabel(String text) {
- super(text);
- setStyleName(CLASSNAME);
- sinkEvents(VTooltip.TOOLTIP_EVENTS);
- }
-
- @Override
- public void onBrowserEvent(Event event) {
- super.onBrowserEvent(event);
- if (event.getTypeInt() == Event.ONLOAD) {
- Util.notifyParentOfSizeChange(this, true);
- event.cancelBubble(true);
- return;
- }
- if (client != null) {
- client.handleTooltipEvent(event, this);
- }
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- this.client = client;
-
- boolean sinkOnloads = false;
-
- final String mode = uidl.getStringAttribute("mode");
- if (mode == null || "text".equals(mode)) {
- setText(uidl.getChildString(0));
- } else if ("pre".equals(mode)) {
- PreElement preElement = Document.get().createPreElement();
- preElement.setInnerText(uidl.getChildUIDL(0).getChildString(0));
- // clear existing content
- setHTML("");
- // add preformatted text to dom
- getElement().appendChild(preElement);
- } else if ("uidl".equals(mode)) {
- setHTML(uidl.getChildrenAsXML());
- } else if ("xhtml".equals(mode)) {
- UIDL content = uidl.getChildUIDL(0).getChildUIDL(0);
- if (content.getChildCount() > 0) {
- setHTML(content.getChildString(0));
- } else {
- setHTML("");
- }
- sinkOnloads = true;
- } else if ("xml".equals(mode)) {
- setHTML(uidl.getChildUIDL(0).getChildString(0));
- } else if ("raw".equals(mode)) {
- setHTML(uidl.getChildUIDL(0).getChildString(0));
- sinkOnloads = true;
- } else {
- setText("");
- }
- if (sinkOnloads) {
- sinkOnloadsForContainedImgs();
- }
- }
-
- private void sinkOnloadsForContainedImgs() {
- NodeList<Element> images = getElement().getElementsByTagName("img");
- for (int i = 0; i < images.getLength(); i++) {
- Element img = images.getItem(i);
- DOM.sinkEvents((com.google.gwt.user.client.Element) img,
- Event.ONLOAD);
- }
-
- }
-
- @Override
- public void setHeight(String height) {
- verticalPaddingBorder = Util.setHeightExcludingPaddingAndBorder(this,
- height, verticalPaddingBorder);
- }
-
- @Override
- public void setWidth(String width) {
- horizontalPaddingBorder = Util.setWidthExcludingPaddingAndBorder(this,
- width, horizontalPaddingBorder);
- if (width == null || width.equals("")) {
- setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, true);
- } else {
- setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, false);
- }
- }
-
- @Override
- public void setText(String text) {
- if (BrowserInfo.get().isIE() && BrowserInfo.get().getIEVersion() < 9) {
- // #3983 - IE6-IE8 incorrectly replaces \n with <br> so we do the
- // escaping manually and set as HTML
- super.setHTML(Util.escapeHTML(text));
- } else {
- super.setText(text);
- }
- }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLink.java b/src/com/vaadin/terminal/gwt/client/ui/VLink.java
index b8030de421..df651c0a4d 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VLink.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VLink.java
@@ -12,42 +12,40 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTML;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VLink extends HTML implements Paintable, ClickHandler {
+public class VLink extends HTML implements ClickHandler {
public static final String CLASSNAME = "v-link";
- private static final int BORDER_STYLE_DEFAULT = 0;
- private static final int BORDER_STYLE_MINIMAL = 1;
- private static final int BORDER_STYLE_NONE = 2;
+ protected static final int BORDER_STYLE_DEFAULT = 0;
+ protected static final int BORDER_STYLE_MINIMAL = 1;
+ protected static final int BORDER_STYLE_NONE = 2;
- private String src;
+ protected String src;
- private String target;
+ protected String target;
- private int borderStyle = BORDER_STYLE_DEFAULT;
+ protected int borderStyle = BORDER_STYLE_DEFAULT;
- private boolean enabled;
+ protected boolean enabled;
- private boolean readonly;
+ protected boolean readonly;
- private int targetWidth;
+ protected int targetWidth;
- private int targetHeight;
+ protected int targetHeight;
- private Element errorIndicatorElement;
+ protected Element errorIndicatorElement;
- private final Element anchor = DOM.createAnchor();
+ protected final Element anchor = DOM.createAnchor();
- private final Element captionElement = DOM.createSpan();
+ protected final Element captionElement = DOM.createSpan();
- private Icon icon;
+ protected Icon icon;
- private ApplicationConnection client;
+ protected ApplicationConnection client;
public VLink() {
super();
@@ -58,68 +56,6 @@ public class VLink extends HTML implements Paintable, ClickHandler {
setStyleName(CLASSNAME);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
- // Ensure correct implementation,
- // but don't let container manage caption etc.
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
-
- this.client = client;
-
- enabled = uidl.hasAttribute("disabled") ? false : true;
- readonly = uidl.hasAttribute("readonly") ? true : false;
-
- if (uidl.hasAttribute("name")) {
- target = uidl.getStringAttribute("name");
- anchor.setAttribute("target", target);
- }
- if (uidl.hasAttribute("src")) {
- src = client.translateVaadinUri(uidl.getStringAttribute("src"));
- anchor.setAttribute("href", src);
- }
-
- if (uidl.hasAttribute("border")) {
- if ("none".equals(uidl.getStringAttribute("border"))) {
- borderStyle = BORDER_STYLE_NONE;
- } else {
- borderStyle = BORDER_STYLE_MINIMAL;
- }
- } else {
- borderStyle = BORDER_STYLE_DEFAULT;
- }
-
- targetHeight = uidl.hasAttribute("targetHeight") ? uidl
- .getIntAttribute("targetHeight") : -1;
- targetWidth = uidl.hasAttribute("targetWidth") ? uidl
- .getIntAttribute("targetWidth") : -1;
-
- // Set link caption
- captionElement.setInnerText(uidl.getStringAttribute("caption"));
-
- // handle error
- if (uidl.hasAttribute("error")) {
- if (errorIndicatorElement == null) {
- errorIndicatorElement = DOM.createDiv();
- DOM.setElementProperty(errorIndicatorElement, "className",
- "v-errorindicator");
- }
- DOM.insertChild(getElement(), errorIndicatorElement, 0);
- } else if (errorIndicatorElement != null) {
- DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
- }
-
- if (uidl.hasAttribute("icon")) {
- if (icon == null) {
- icon = new Icon(client);
- anchor.insertBefore(icon.getElement(), captionElement);
- }
- icon.setUri(uidl.getStringAttribute("icon"));
- }
-
- }
-
public void onClick(ClickEvent event) {
if (enabled && !readonly) {
if (target == null) {
@@ -167,7 +103,7 @@ public class VLink extends HTML implements Paintable, ClickHandler {
Util.notifyParentOfSizeChange(this, true);
}
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
if (target == captionElement || target == anchor
|| (icon != null && target == icon.getElement())) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLinkPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VLinkPaintable.java
new file mode 100644
index 0000000000..3fbd796c4b
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VLinkPaintable.java
@@ -0,0 +1,100 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VLinkPaintable extends VAbstractPaintableWidget {
+
+ 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;
+ }
+
+ getWidgetForPaintable().client = client;
+
+ getWidgetForPaintable().enabled = uidl.hasAttribute("disabled") ? false
+ : true;
+ getWidgetForPaintable().readonly = uidl.hasAttribute("readonly") ? true
+ : false;
+
+ if (uidl.hasAttribute("name")) {
+ getWidgetForPaintable().target = uidl.getStringAttribute("name");
+ getWidgetForPaintable().anchor.setAttribute("target",
+ getWidgetForPaintable().target);
+ }
+ if (uidl.hasAttribute("src")) {
+ getWidgetForPaintable().src = client.translateVaadinUri(uidl
+ .getStringAttribute("src"));
+ getWidgetForPaintable().anchor.setAttribute("href",
+ getWidgetForPaintable().src);
+ }
+
+ if (uidl.hasAttribute("border")) {
+ if ("none".equals(uidl.getStringAttribute("border"))) {
+ getWidgetForPaintable().borderStyle = VLink.BORDER_STYLE_NONE;
+ } else {
+ getWidgetForPaintable().borderStyle = VLink.BORDER_STYLE_MINIMAL;
+ }
+ } else {
+ getWidgetForPaintable().borderStyle = VLink.BORDER_STYLE_DEFAULT;
+ }
+
+ getWidgetForPaintable().targetHeight = uidl
+ .hasAttribute("targetHeight") ? uidl
+ .getIntAttribute("targetHeight") : -1;
+ getWidgetForPaintable().targetWidth = uidl.hasAttribute("targetWidth") ? uidl
+ .getIntAttribute("targetWidth") : -1;
+
+ // Set link caption
+ getWidgetForPaintable().captionElement.setInnerText(uidl
+ .getStringAttribute("caption"));
+
+ // handle error
+ if (uidl.hasAttribute("error")) {
+ if (getWidgetForPaintable().errorIndicatorElement == null) {
+ getWidgetForPaintable().errorIndicatorElement = DOM.createDiv();
+ DOM.setElementProperty(
+ getWidgetForPaintable().errorIndicatorElement,
+ "className", "v-errorindicator");
+ }
+ DOM.insertChild(getWidgetForPaintable().getElement(),
+ getWidgetForPaintable().errorIndicatorElement, 0);
+ } else if (getWidgetForPaintable().errorIndicatorElement != null) {
+ DOM.setStyleAttribute(
+ getWidgetForPaintable().errorIndicatorElement, "display",
+ "none");
+ }
+
+ if (uidl.hasAttribute("icon")) {
+ if (getWidgetForPaintable().icon == null) {
+ getWidgetForPaintable().icon = new Icon(client);
+ getWidgetForPaintable().anchor.insertBefore(
+ getWidgetForPaintable().icon.getElement(),
+ getWidgetForPaintable().captionElement);
+ }
+ getWidgetForPaintable().icon
+ .setUri(uidl.getStringAttribute("icon"));
+ }
+
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VLink.class);
+ }
+
+ @Override
+ public VLink getWidgetForPaintable() {
+ return (VLink) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java
index cebc4600a2..1ea2f4f705 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java
@@ -10,8 +10,8 @@ import java.util.Iterator;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VTooltip;
@@ -80,11 +80,11 @@ public class VListSelect extends VOptionGroupBase {
} else {
lastSelectedIndex = si;
if (isMultiselect()) {
- client.updateVariable(id, "selected", getSelectedItems(),
- isImmediate());
+ client.updateVariable(paintableId, "selected",
+ getSelectedItems(), isImmediate());
} else {
- client.updateVariable(id, "selected", new String[] { ""
- + getSelectedItem() }, isImmediate());
+ client.updateVariable(paintableId, "selected",
+ new String[] { "" + getSelectedItem() }, isImmediate());
}
}
}
@@ -109,7 +109,6 @@ public class VListSelect extends VOptionGroupBase {
public void focus() {
select.setFocus(true);
}
-
}
/**
@@ -118,7 +117,7 @@ public class VListSelect extends VOptionGroupBase {
*/
class TooltipListBox extends ListBox {
private ApplicationConnection client;
- private Paintable pntbl;
+ private Widget widget;
TooltipListBox(boolean isMultiselect) {
super(isMultiselect);
@@ -129,15 +128,16 @@ class TooltipListBox extends ListBox {
this.client = client;
}
- public void setSelect(Paintable s) {
- pntbl = s;
+ public void setSelect(Widget widget) {
+ this.widget = widget;
}
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, pntbl);
+ client.handleWidgetTooltipEvent(event, widget);
}
}
+
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VListSelectPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VListSelectPaintable.java
new file mode 100644
index 0000000000..b77bfa33e3
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VListSelectPaintable.java
@@ -0,0 +1,21 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+
+public class VListSelectPaintable extends VOptionGroupBasePaintable {
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VListSelect.class);
+ }
+
+ @Override
+ public VListSelect getWidgetForPaintable() {
+ return (VListSelect) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java b/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java
index 53638917b2..6c5fbc2ef0 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java
@@ -8,25 +8,10 @@ import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.MediaElement;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-public abstract class VMediaBase extends Widget implements Paintable {
- public static final String ATTR_PAUSE = "pause";
- public static final String ATTR_PLAY = "play";
- public static final String ATTR_MUTED = "muted";
- public static final String ATTR_CONTROLS = "ctrl";
- public static final String ATTR_AUTOPLAY = "auto";
- public static final String TAG_SOURCE = "src";
- public static final String ATTR_RESOURCE = "res";
- public static final String ATTR_RESOURCE_TYPE = "type";
- public static final String ATTR_HTML = "html";
- public static final String ATTR_ALT_TEXT = "alt";
+public abstract class VMediaBase extends Widget {
private MediaElement media;
- protected ApplicationConnection client;
/**
* Sets the MediaElement that is to receive all commands and properties.
@@ -38,96 +23,40 @@ public abstract class VMediaBase extends Widget implements Paintable {
media = element;
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- this.client = client;
-
- media.setControls(shouldShowControls(uidl));
- media.setAutoplay(shouldAutoplay(uidl));
- media.setMuted(isMediaMuted(uidl));
-
- // Add all sources
- for (int ix = 0; ix < uidl.getChildCount(); ix++) {
- UIDL child = uidl.getChildUIDL(ix);
- if (TAG_SOURCE.equals(child.getTag())) {
- Element src = Document.get().createElement("source").cast();
- src.setAttribute("src", getSourceUrl(child));
- src.setAttribute("type", getSourceType(child));
- media.appendChild(src);
- }
- }
- setAltText(uidl);
-
- evalPauseCommand(uidl);
- evalPlayCommand(uidl);
- }
-
- protected boolean shouldShowControls(UIDL uidl) {
- return uidl.getBooleanAttribute(ATTR_CONTROLS);
- }
-
- private boolean shouldAutoplay(UIDL uidl) {
- return uidl.getBooleanAttribute(ATTR_AUTOPLAY);
- }
-
- private boolean isMediaMuted(UIDL uidl) {
- return uidl.getBooleanAttribute(ATTR_MUTED);
- }
-
/**
- * @param uidl
- * @return the URL of a resource to be used as a source for the media
+ * @return the default HTML to show users with browsers that do not support
+ * HTML5 media markup.
*/
- private String getSourceUrl(UIDL uidl) {
- String url = client.translateVaadinUri(uidl
- .getStringAttribute(ATTR_RESOURCE));
- if (url == null) {
- return "";
- }
- return url;
- }
+ protected abstract String getDefaultAltHtml();
- /**
- * @param uidl
- * @return the mime type of the media
- */
- private String getSourceType(UIDL uidl) {
- return uidl.getStringAttribute(ATTR_RESOURCE_TYPE);
+ public void play() {
+ media.play();
}
- private void setAltText(UIDL uidl) {
- String alt = uidl.getStringAttribute(ATTR_ALT_TEXT);
+ public void pause() {
+ media.pause();
+ }
- if (alt == null || "".equals(alt)) {
- alt = getDefaultAltHtml();
- } else if (!allowHtmlContent(uidl)) {
- alt = Util.escapeHTML(alt);
- }
+ public void setAltText(String alt) {
media.appendChild(Document.get().createTextNode(alt));
}
- private boolean allowHtmlContent(UIDL uidl) {
- return uidl.getBooleanAttribute(ATTR_HTML);
+ public void setControls(boolean shouldShowControls) {
+ media.setControls(shouldShowControls);
}
- private void evalPlayCommand(UIDL uidl) {
- if (uidl.hasAttribute(ATTR_PLAY)) {
- media.play();
- }
+ public void setAutoplay(boolean shouldAutoplay) {
+ media.setAutoplay(shouldAutoplay);
}
- private void evalPauseCommand(UIDL uidl) {
- if (uidl.hasAttribute(ATTR_PAUSE)) {
- media.pause();
- }
+ public void setMuted(boolean mediaMuted) {
+ media.setMuted(mediaMuted);
}
- /**
- * @return the default HTML to show users with browsers that do not support
- * HTML5 media markup.
- */
- protected abstract String getDefaultAltHtml();
+ public void addSource(String sourceUrl, String sourceType) {
+ Element src = Document.get().createElement("source").cast();
+ src.setAttribute("src", sourceUrl);
+ src.setAttribute("type", sourceType);
+ media.appendChild(src);
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMediaBasePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VMediaBasePaintable.java
new file mode 100644
index 0000000000..bef770f38b
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VMediaBasePaintable.java
@@ -0,0 +1,109 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public abstract class VMediaBasePaintable extends VAbstractPaintableWidget {
+
+ public static final String TAG_SOURCE = "src";
+
+ public static final String ATTR_PAUSE = "pause";
+ public static final String ATTR_PLAY = "play";
+ public static final String ATTR_MUTED = "muted";
+ public static final String ATTR_CONTROLS = "ctrl";
+ public static final String ATTR_AUTOPLAY = "auto";
+ public static final String ATTR_RESOURCE = "res";
+ public static final String ATTR_RESOURCE_TYPE = "type";
+ public static final String ATTR_HTML = "html";
+ public static final String ATTR_ALT_TEXT = "alt";
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ getWidgetForPaintable().setControls(shouldShowControls(uidl));
+ getWidgetForPaintable().setAutoplay(shouldAutoplay(uidl));
+ getWidgetForPaintable().setMuted(isMediaMuted(uidl));
+
+ // Add all sources
+ for (int ix = 0; ix < uidl.getChildCount(); ix++) {
+ UIDL child = uidl.getChildUIDL(ix);
+ if (TAG_SOURCE.equals(child.getTag())) {
+ getWidgetForPaintable().addSource(getSourceUrl(child),
+ getSourceType(child));
+ }
+ }
+ setAltText(uidl);
+
+ evalPauseCommand(uidl);
+ evalPlayCommand(uidl);
+ }
+
+ protected boolean shouldShowControls(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_CONTROLS);
+ }
+
+ private boolean shouldAutoplay(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_AUTOPLAY);
+ }
+
+ private boolean isMediaMuted(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_MUTED);
+ }
+
+ private boolean allowHtmlContent(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_HTML);
+ }
+
+ private void evalPlayCommand(UIDL uidl) {
+ if (uidl.hasAttribute(ATTR_PLAY)) {
+ getWidgetForPaintable().play();
+ }
+ }
+
+ private void evalPauseCommand(UIDL uidl) {
+ if (uidl.hasAttribute(ATTR_PAUSE)) {
+ getWidgetForPaintable().pause();
+ }
+ }
+
+ @Override
+ public VMediaBase getWidgetForPaintable() {
+ return (VMediaBase) super.getWidgetForPaintable();
+ }
+
+ /**
+ * @param uidl
+ * @return the URL of a resource to be used as a source for the media
+ */
+ private String getSourceUrl(UIDL uidl) {
+ String url = getConnection().translateVaadinUri(
+ uidl.getStringAttribute(VMediaBasePaintable.ATTR_RESOURCE));
+ if (url == null) {
+ return "";
+ }
+ return url;
+ }
+
+ /**
+ * @param uidl
+ * @return the mime type of the media
+ */
+ private String getSourceType(UIDL uidl) {
+ return uidl.getStringAttribute(VMediaBasePaintable.ATTR_RESOURCE_TYPE);
+ }
+
+ private void setAltText(UIDL uidl) {
+ String alt = uidl.getStringAttribute(VMediaBasePaintable.ATTR_ALT_TEXT);
+
+ if (alt == null || "".equals(alt)) {
+ alt = getWidgetForPaintable().getDefaultAltHtml();
+ } else if (!allowHtmlContent(uidl)) {
+ alt = Util.escapeHTML(alt);
+ }
+ getWidgetForPaintable().setAltText(alt);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
index a0d7300f11..c39155d032 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
@@ -4,14 +4,11 @@
package com.vaadin.terminal.gwt.client.ui;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-import java.util.Stack;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Unit;
@@ -36,13 +33,12 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.TooltipInfo;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VMenuBar extends SimpleFocusablePanel implements Paintable,
+public class VMenuBar extends SimpleFocusablePanel implements
CloseHandler<PopupPanel>, ContainerResizedListener, KeyPressHandler,
KeyDownHandler, FocusHandler, SubPartAware {
@@ -57,7 +53,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
protected ApplicationConnection client;
protected final VMenuBar hostReference = this;
- protected String submenuIcon = null;
protected CustomMenuItem moreItem = null;
// Only used by the root menu bar
@@ -83,7 +78,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
protected VMenuBar parentMenu;
protected CustomMenuItem selected;
- private boolean enabled = true;
+ boolean enabled = true;
private String width = "notinited";
@@ -95,9 +90,9 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
}
});
- private boolean openRootOnHover;
+ boolean openRootOnHover;
- private boolean htmlContentAllowed;
+ boolean htmlContentAllowed;
public VMenuBar() {
// Create an empty horizontal menubar
@@ -157,24 +152,9 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
}
this.width = width;
- if (BrowserInfo.get().isIE6() && width.endsWith("px")) {
- // IE6 sometimes measures wrong using
- // Util.setWidthExcludingPaddingAndBorder so this is extracted to a
- // special case that uses another method. Really should fix the
- // Util.setWidthExcludingPaddingAndBorder method but that will
- // probably break additional cases
- int requestedPixelWidth = Integer.parseInt(width.substring(0,
- width.length() - 2));
- int paddingBorder = Util.measureHorizontalPaddingAndBorder(
- getElement(), 0);
- int w = requestedPixelWidth - paddingBorder;
- if (w < 0) {
- w = 0;
- }
- getElement().getStyle().setWidth(w, Unit.PX);
- } else {
- Util.setWidthExcludingPaddingAndBorder(this, width, 0);
- }
+
+ Util.setWidthExcludingPaddingAndBorder(this, width, 0);
+
if (!subMenu) {
// Only needed for root level menu
hideChildren();
@@ -184,141 +164,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
}
/**
- * This method must be implemented to update the client-side component from
- * UIDL data received from server.
- *
- * This method is called when the page is loaded for the first time, and
- * every time UI changes in the component are received from the server.
- */
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // This call should be made first. Ensure correct implementation,
- // and let the containing layout manage caption, etc.
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- htmlContentAllowed = uidl.hasAttribute(HTML_CONTENT_ALLOWED);
-
- openRootOnHover = uidl.getBooleanAttribute(OPEN_ROOT_MENU_ON_HOWER);
-
- enabled = !uidl.getBooleanAttribute("disabled");
-
- // For future connections
- this.client = client;
- uidlId = uidl.getId();
-
- // Empty the menu every time it receives new information
- if (!getItems().isEmpty()) {
- clearItems();
- }
-
- UIDL options = uidl.getChildUIDL(0);
-
- // FIXME remove in version 7
- if (options.hasAttribute("submenuIcon")) {
- submenuIcon = client.translateVaadinUri(uidl.getChildUIDL(0)
- .getStringAttribute("submenuIcon"));
- } else {
- submenuIcon = null;
- }
-
- if (uidl.hasAttribute("width")) {
- UIDL moreItemUIDL = options.getChildUIDL(0);
- StringBuffer itemHTML = new StringBuffer();
-
- if (moreItemUIDL.hasAttribute("icon")) {
- itemHTML.append("<img src=\""
- + Util.escapeAttribute(client
- .translateVaadinUri(moreItemUIDL
- .getStringAttribute("icon")))
- + "\" class=\"" + Icon.CLASSNAME + "\" alt=\"\" />");
- }
-
- String moreItemText = moreItemUIDL.getStringAttribute("text");
- if ("".equals(moreItemText)) {
- moreItemText = "&#x25BA;";
- }
- itemHTML.append(moreItemText);
-
- moreItem = GWT.create(CustomMenuItem.class);
- moreItem.setHTML(itemHTML.toString());
- moreItem.setCommand(emptyCommand);
-
- collapsedRootItems = new VMenuBar(true,
- (VMenuBar) client.getPaintable(uidlId));
- moreItem.setSubMenu(collapsedRootItems);
- moreItem.addStyleName(CLASSNAME + "-more-menuitem");
- }
-
- UIDL uidlItems = uidl.getChildUIDL(1);
- Iterator<Object> itr = uidlItems.getChildIterator();
- Stack<Iterator<Object>> iteratorStack = new Stack<Iterator<Object>>();
- Stack<VMenuBar> menuStack = new Stack<VMenuBar>();
- VMenuBar currentMenu = this;
-
- while (itr.hasNext()) {
- UIDL item = (UIDL) itr.next();
- CustomMenuItem currentItem = null;
-
- final int itemId = item.getIntAttribute("id");
-
- boolean itemHasCommand = item.hasAttribute("command");
- boolean itemIsCheckable = item.hasAttribute(ATTRIBUTE_CHECKED);
-
- String itemHTML = buildItemHTML(item);
-
- Command cmd = null;
- if (!item.hasAttribute("separator")) {
- if (itemHasCommand || itemIsCheckable) {
- // Construct a command that fires onMenuClick(int) with the
- // item's id-number
- cmd = new Command() {
- public void execute() {
- hostReference.onMenuClick(itemId);
- }
- };
- }
- }
-
- currentItem = currentMenu.addItem(itemHTML.toString(), cmd);
- currentItem.updateFromUIDL(item, client);
-
- if (item.getChildCount() > 0) {
- menuStack.push(currentMenu);
- iteratorStack.push(itr);
- itr = item.getChildIterator();
- currentMenu = new VMenuBar(true, currentMenu);
- if (uidl.hasAttribute("style")) {
- for (String style : uidl.getStringAttribute("style").split(
- " ")) {
- currentMenu.addStyleDependentName(style);
- }
- }
- currentItem.setSubMenu(currentMenu);
- }
-
- while (!itr.hasNext() && !iteratorStack.empty()) {
- boolean hasCheckableItem = false;
- for (CustomMenuItem menuItem : currentMenu.getItems()) {
- hasCheckableItem = hasCheckableItem
- || menuItem.isCheckable();
- }
- if (hasCheckableItem) {
- currentMenu.addStyleDependentName("check-column");
- } else {
- currentMenu.removeStyleDependentName("check-column");
- }
-
- itr = iteratorStack.pop();
- currentMenu = menuStack.pop();
- }
- }// while
-
- iLayout(false);
-
- }// updateFromUIDL
-
- /**
* Build the HTML content for a menu item.
*
* @param item
@@ -332,13 +177,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
} else {
// Add submenu indicator
if (item.getChildCount() > 0) {
- // FIXME For compatibility reasons: remove in version 7
String bgStyle = "";
- if (submenuIcon != null) {
- bgStyle = " style=\"background-image: url("
- + Util.escapeAttribute(submenuIcon)
- + "); text-indent: -999px; width: 1em;\"";
- }
itemHTML.append("<span class=\"" + CLASSNAME
+ "-submenu-indicator\"" + bgStyle + ">&#x25BA;</span>");
}
@@ -478,9 +317,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
// Handle onload events (icon loaded, size changes)
if (DOM.eventGetType(e) == Event.ONLOAD) {
- if (BrowserInfo.get().isIE6()) {
- Util.doIE6PngFix((Element) Element.as(e.getEventTarget()));
- }
VMenuBar parent = getParentMenu();
if (parent != null) {
// The onload event for an image in a popup should be sent to
@@ -506,7 +342,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
// Handle tooltips
if (targetItem == null && client != null) {
// Handle root menubar tooltips
- client.handleTooltipEvent(e, this);
+ client.handleWidgetTooltipEvent(e, this);
} else if (targetItem != null) {
// Handle item tooltips
targetItem.onBrowserEvent(e);
@@ -733,27 +569,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
popup.setPopupPosition(left, top);
- // IE7 really tests one's patience sometimes
- // Part of a fix to correct #3850
- if (BrowserInfo.get().isIE7()) {
- popup.getElement().getStyle().setProperty("zoom", "");
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- if (popup == null) {
- // The child menu can be hidden before this command is
- // run.
- return;
- }
-
- if (popup.getElement().getStyle().getProperty("width") == null
- || popup.getElement().getStyle()
- .getProperty("width") == "") {
- popup.setWidth(popup.getOffsetWidth() + "px");
- }
- popup.getElement().getStyle().setProperty("zoom", "1");
- }
- });
- }
}
private int adjustPopupHeight(int top, final int shadowSpace) {
@@ -780,19 +595,10 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
style.setHeight(availableHeight, Unit.PX);
style.setOverflowY(Overflow.SCROLL);
- // Make room for the scroll bar
- if (BrowserInfo.get().isIE6()) {
- // IE6 renders the sub menu arrow icons on the scroll bar
- // unless we add some padding
- style.setPaddingRight(Util.getNativeScrollbarSize(),
- Unit.PX);
- } else {
- // For other browsers, adjusting the width of the popup is
- // enough
- style.setWidth(
- contentWidth + Util.getNativeScrollbarSize(),
- Unit.PX);
- }
+ // Make room for the scroll bar by adjusting the width of the
+ // popup
+ style.setWidth(contentWidth + Util.getNativeScrollbarSize(),
+ Unit.PX);
popup.updateShadowSizeAndPosition();
}
}
@@ -962,6 +768,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
addStyleDependentName("selected");
// needed for IE6 to have a single style name to match for an
// element
+ // TODO Can be optimized now that IE6 is not supported any more
if (checkable) {
if (checked) {
removeStyleDependentName("selected-unchecked");
@@ -1113,7 +920,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
TooltipInfo info = new TooltipInfo(description);
VMenuBar root = findRootMenu();
- client.registerTooltip(root, this, info);
+ client.registerWidgetTooltip(root, this, info);
}
}
@@ -1121,7 +928,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, findRootMenu(), this);
+ client.handleWidgetTooltipEvent(event, findRootMenu(), this);
}
}
@@ -1170,22 +977,9 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
paddingWidth = widthBefore - getElement().getClientWidth();
getElement().getStyle().setProperty("padding", "");
}
- String overflow = "";
- if (BrowserInfo.get().isIE6()) {
- // IE6 cannot measure available width correctly without
- // overflow:hidden
- overflow = getElement().getStyle().getProperty("overflow");
- getElement().getStyle().setProperty("overflow", "hidden");
- }
int availableWidth = getElement().getClientWidth() - paddingWidth;
- if (BrowserInfo.get().isIE6()) {
- // IE6 cannot measure available width correctly without
- // overflow:hidden
- getElement().getStyle().setProperty("overflow", overflow);
- }
-
// Used width includes the "more" item if present
int usedWidth = getConsumedWidth();
int diff = availableWidth - usedWidth;
@@ -1230,16 +1024,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
} else {
widthAvailable = diff;
}
-
- if (BrowserInfo.get().isIE6()) {
- /*
- * Handle transparency for IE6 here as we cannot
- * implement it in CustomMenuItem.onAttach because
- * onAttach is never called for CustomMenuItem due to an
- * invalid component hierarchy (#6203)...
- */
- reloadImages(expand.getElement());
- }
}
}
if (collapsedRootItems.getItems().size() > 0) {
@@ -1636,31 +1420,4 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable,
return null;
}
- @Override
- protected void onLoad() {
- super.onLoad();
- if (BrowserInfo.get().isIE6()) {
- reloadImages(getElement());
- }
- }
-
- /**
- * Force a new onload event for all images. Used only for IE6 to deal with
- * PNG transparency.
- */
- private void reloadImages(Element root) {
-
- NodeList<com.google.gwt.dom.client.Element> imgElements = root
- .getElementsByTagName("img");
- for (int i = 0; i < imgElements.getLength(); i++) {
- Element e = (Element) imgElements.getItem(i);
-
- // IE6 fires onload events for the icons before the listener
- // is attached (or never). Updating the src force another
- // onload event
- String src = e.getAttribute("src");
- e.setAttribute("src", src);
- }
- }
-
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java
new file mode 100644
index 0000000000..ef2a49b9d0
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java
@@ -0,0 +1,161 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+import java.util.Stack;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.ui.VMenuBar.CustomMenuItem;
+
+public class VMenuBarPaintable extends VAbstractPaintableWidget {
+ /**
+ * 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;
+ }
+
+ getWidgetForPaintable().htmlContentAllowed = uidl
+ .hasAttribute(VMenuBar.HTML_CONTENT_ALLOWED);
+
+ getWidgetForPaintable().openRootOnHover = uidl
+ .getBooleanAttribute(VMenuBar.OPEN_ROOT_MENU_ON_HOWER);
+
+ getWidgetForPaintable().enabled = !uidl.getBooleanAttribute("disabled");
+
+ // For future connections
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().uidlId = uidl.getId();
+
+ // Empty the menu every time it receives new information
+ if (!getWidgetForPaintable().getItems().isEmpty()) {
+ getWidgetForPaintable().clearItems();
+ }
+
+ UIDL options = uidl.getChildUIDL(0);
+
+ if (uidl.hasAttribute("width")) {
+ UIDL moreItemUIDL = options.getChildUIDL(0);
+ StringBuffer itemHTML = new StringBuffer();
+
+ if (moreItemUIDL.hasAttribute("icon")) {
+ itemHTML.append("<img src=\""
+ + Util.escapeAttribute(client
+ .translateVaadinUri(moreItemUIDL
+ .getStringAttribute("icon")))
+ + "\" class=\"" + Icon.CLASSNAME + "\" alt=\"\" />");
+ }
+
+ String moreItemText = moreItemUIDL.getStringAttribute("text");
+ if ("".equals(moreItemText)) {
+ moreItemText = "&#x25BA;";
+ }
+ itemHTML.append(moreItemText);
+
+ getWidgetForPaintable().moreItem = GWT.create(CustomMenuItem.class);
+ getWidgetForPaintable().moreItem.setHTML(itemHTML.toString());
+ getWidgetForPaintable().moreItem.setCommand(VMenuBar.emptyCommand);
+
+ getWidgetForPaintable().collapsedRootItems = new VMenuBar(true,
+ getWidgetForPaintable());
+ getWidgetForPaintable().moreItem
+ .setSubMenu(getWidgetForPaintable().collapsedRootItems);
+ getWidgetForPaintable().moreItem.addStyleName(VMenuBar.CLASSNAME
+ + "-more-menuitem");
+ }
+
+ UIDL uidlItems = uidl.getChildUIDL(1);
+ Iterator<Object> itr = uidlItems.getChildIterator();
+ Stack<Iterator<Object>> iteratorStack = new Stack<Iterator<Object>>();
+ Stack<VMenuBar> menuStack = new Stack<VMenuBar>();
+ VMenuBar currentMenu = getWidgetForPaintable();
+
+ while (itr.hasNext()) {
+ UIDL item = (UIDL) itr.next();
+ CustomMenuItem currentItem = null;
+
+ final int itemId = item.getIntAttribute("id");
+
+ boolean itemHasCommand = item.hasAttribute("command");
+ boolean itemIsCheckable = item
+ .hasAttribute(VMenuBar.ATTRIBUTE_CHECKED);
+
+ String itemHTML = getWidgetForPaintable().buildItemHTML(item);
+
+ Command cmd = null;
+ if (!item.hasAttribute("separator")) {
+ if (itemHasCommand || itemIsCheckable) {
+ // Construct a command that fires onMenuClick(int) with the
+ // item's id-number
+ cmd = new Command() {
+ public void execute() {
+ getWidgetForPaintable().hostReference
+ .onMenuClick(itemId);
+ }
+ };
+ }
+ }
+
+ currentItem = currentMenu.addItem(itemHTML.toString(), cmd);
+ currentItem.updateFromUIDL(item, client);
+
+ if (item.getChildCount() > 0) {
+ menuStack.push(currentMenu);
+ iteratorStack.push(itr);
+ itr = item.getChildIterator();
+ currentMenu = new VMenuBar(true, currentMenu);
+ if (uidl.hasAttribute("style")) {
+ for (String style : uidl.getStringAttribute("style").split(
+ " ")) {
+ currentMenu.addStyleDependentName(style);
+ }
+ }
+ currentItem.setSubMenu(currentMenu);
+ }
+
+ while (!itr.hasNext() && !iteratorStack.empty()) {
+ boolean hasCheckableItem = false;
+ for (CustomMenuItem menuItem : currentMenu.getItems()) {
+ hasCheckableItem = hasCheckableItem
+ || menuItem.isCheckable();
+ }
+ if (hasCheckableItem) {
+ currentMenu.addStyleDependentName("check-column");
+ } else {
+ currentMenu.removeStyleDependentName("check-column");
+ }
+
+ itr = iteratorStack.pop();
+ currentMenu = menuStack.pop();
+ }
+ }// while
+
+ getWidgetForPaintable().iLayout(false);
+
+ }// updateFromUIDL
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VMenuBar.class);
+ }
+
+ @Override
+ public VMenuBar getWidgetForPaintable() {
+ return (VMenuBar) super.getWidgetForPaintable();
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
index 98d3b505ae..94e5cdf40c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
@@ -4,7 +4,6 @@
package com.vaadin.terminal.gwt.client.ui;
-import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -13,28 +12,24 @@ import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Button;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.EventHelper;
import com.vaadin.terminal.gwt.client.EventId;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VNativeButton extends Button implements Paintable, ClickHandler,
+public class VNativeButton extends Button implements ClickHandler,
FocusHandler, BlurHandler {
public static final String CLASSNAME = "v-nativebutton";
protected String width = null;
- protected String id;
+ protected String paintableId;
protected ApplicationConnection client;
@@ -51,10 +46,10 @@ public class VNativeButton extends Button implements Paintable, ClickHandler,
*/
private boolean clickPending;
- private HandlerRegistration focusHandlerRegistration;
- private HandlerRegistration blurHandlerRegistration;
+ protected HandlerRegistration focusHandlerRegistration;
+ protected HandlerRegistration blurHandlerRegistration;
- private boolean disableOnClick = false;
+ protected boolean disableOnClick = false;
public VNativeButton() {
setStyleName(CLASSNAME);
@@ -69,76 +64,6 @@ public class VNativeButton extends Button implements Paintable, ClickHandler,
sinkEvents(Event.ONMOUSEUP);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
- // Ensure correct implementation,
- // but don't let container manage caption etc.
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
-
- disableOnClick = uidl.hasAttribute(VButton.ATTR_DISABLE_ON_CLICK);
-
- focusHandlerRegistration = EventHelper.updateFocusHandler(this, client,
- focusHandlerRegistration);
- blurHandlerRegistration = EventHelper.updateBlurHandler(this, client,
- blurHandlerRegistration);
-
- // Save details
- this.client = client;
- id = uidl.getId();
-
- // Set text
- setText(uidl.getStringAttribute("caption"));
-
- // handle error
- if (uidl.hasAttribute("error")) {
- if (errorIndicatorElement == null) {
- errorIndicatorElement = DOM.createSpan();
- errorIndicatorElement.setClassName("v-errorindicator");
- }
- getElement().insertBefore(errorIndicatorElement, captionElement);
-
- // Fix for IE6, IE7
- if (BrowserInfo.get().isIE()) {
- errorIndicatorElement.setInnerText(" ");
- }
-
- } else if (errorIndicatorElement != null) {
- getElement().removeChild(errorIndicatorElement);
- errorIndicatorElement = null;
- }
-
- if (uidl.hasAttribute("icon")) {
- if (icon == null) {
- icon = new Icon(client);
- getElement().insertBefore(icon.getElement(), captionElement);
- }
- icon.setUri(uidl.getStringAttribute("icon"));
- } else {
- if (icon != null) {
- getElement().removeChild(icon.getElement());
- icon = null;
- }
- }
-
- if (BrowserInfo.get().isIE7()) {
- /*
- * Workaround for IE7 size calculation issues. Deferred because of
- * issues with a button with an icon using the reindeer theme
- */
- if (width.equals("")) {
- Scheduler.get().scheduleDeferred(new Command() {
-
- public void execute() {
- setWidth("");
- setWidth(getOffsetWidth() + "px");
- }
- });
- }
- }
- }
-
@Override
public void setText(String text) {
captionElement.setInnerText(text);
@@ -164,30 +89,14 @@ public class VNativeButton extends Button implements Paintable, ClickHandler,
}
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
}
@Override
public void setWidth(String width) {
- /* Workaround for IE7 button size part 1 (#2014) */
- if (BrowserInfo.get().isIE7() && this.width != null) {
- if (this.width.equals(width)) {
- return;
- }
-
- if (width == null) {
- width = "";
- }
- }
-
this.width = width;
super.setWidth(width);
-
- /* Workaround for IE7 button size part 2 (#2014) */
- if (BrowserInfo.get().isIE7()) {
- super.setWidth(width);
- }
}
/*
@@ -198,7 +107,7 @@ public class VNativeButton extends Button implements Paintable, ClickHandler,
* .dom.client.ClickEvent)
*/
public void onClick(ClickEvent event) {
- if (id == null || client == null) {
+ if (paintableId == null || client == null) {
return;
}
@@ -207,24 +116,25 @@ public class VNativeButton extends Button implements Paintable, ClickHandler,
}
if (disableOnClick) {
setEnabled(false);
- client.updateVariable(id, "disabledOnClick", true, false);
+ client.updateVariable(paintableId, "disabledOnClick", true, false);
}
// Add mouse details
MouseEventDetails details = new MouseEventDetails(
event.getNativeEvent(), getElement());
- client.updateVariable(id, "mousedetails", details.serialize(), false);
+ client.updateVariable(paintableId, "mousedetails", details.serialize(),
+ false);
- client.updateVariable(id, "state", true, true);
+ client.updateVariable(paintableId, "state", true, true);
clickPending = false;
}
public void onFocus(FocusEvent arg0) {
- client.updateVariable(id, EventId.FOCUS, "", true);
+ client.updateVariable(paintableId, EventId.FOCUS, "", true);
}
public void onBlur(BlurEvent arg0) {
- client.updateVariable(id, EventId.BLUR, "", true);
+ client.updateVariable(paintableId, EventId.BLUR, "", true);
}
@Override
@@ -234,5 +144,4 @@ public class VNativeButton extends Button implements Paintable, ClickHandler,
setStyleName(ApplicationConnection.DISABLED_CLASSNAME, !enabled);
}
}
-
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeButtonPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeButtonPaintable.java
new file mode 100644
index 0000000000..ebf9cad264
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeButtonPaintable.java
@@ -0,0 +1,86 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.EventHelper;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VNativeButtonPaintable extends VAbstractPaintableWidget {
+
+ 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;
+ }
+
+ getWidgetForPaintable().disableOnClick = uidl
+ .hasAttribute(VButton.ATTR_DISABLE_ON_CLICK);
+
+ getWidgetForPaintable().focusHandlerRegistration = EventHelper
+ .updateFocusHandler(this, client,
+ getWidgetForPaintable().focusHandlerRegistration);
+ getWidgetForPaintable().blurHandlerRegistration = EventHelper
+ .updateBlurHandler(this, client,
+ getWidgetForPaintable().blurHandlerRegistration);
+
+ // Save details
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getId();
+
+ // Set text
+ getWidgetForPaintable().setText(uidl.getStringAttribute("caption"));
+
+ // handle error
+ if (uidl.hasAttribute("error")) {
+ if (getWidgetForPaintable().errorIndicatorElement == null) {
+ getWidgetForPaintable().errorIndicatorElement = DOM
+ .createSpan();
+ getWidgetForPaintable().errorIndicatorElement
+ .setClassName("v-errorindicator");
+ }
+ getWidgetForPaintable().getElement().insertBefore(
+ getWidgetForPaintable().errorIndicatorElement,
+ getWidgetForPaintable().captionElement);
+
+ } else if (getWidgetForPaintable().errorIndicatorElement != null) {
+ getWidgetForPaintable().getElement().removeChild(
+ getWidgetForPaintable().errorIndicatorElement);
+ getWidgetForPaintable().errorIndicatorElement = null;
+ }
+
+ if (uidl.hasAttribute("icon")) {
+ if (getWidgetForPaintable().icon == null) {
+ getWidgetForPaintable().icon = new Icon(client);
+ getWidgetForPaintable().getElement().insertBefore(
+ getWidgetForPaintable().icon.getElement(),
+ getWidgetForPaintable().captionElement);
+ }
+ getWidgetForPaintable().icon
+ .setUri(uidl.getStringAttribute("icon"));
+ } else {
+ if (getWidgetForPaintable().icon != null) {
+ getWidgetForPaintable().getElement().removeChild(
+ getWidgetForPaintable().icon.getElement());
+ getWidgetForPaintable().icon = null;
+ }
+ }
+
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VNativeButton.class);
+ }
+
+ @Override
+ public VNativeButton getWidgetForPaintable() {
+ return (VNativeButton) super.getWidgetForPaintable();
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java
index d1b2bd76ae..ec2f6e42a1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java
@@ -8,9 +8,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import com.google.gwt.event.dom.client.ChangeEvent;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
public class VNativeSelect extends VOptionGroupBase implements Field {
@@ -58,11 +56,6 @@ public class VNativeSelect extends VOptionGroupBase implements Field {
select.setItemSelected(0, true);
firstValueIsTemporaryNullItem = true;
}
- if (BrowserInfo.get().isIE6()) {
- // lazy size change - IE6 uses naive dropdown that does not have a
- // proper size yet
- Util.notifyParentOfSizeChange(this, true);
- }
}
@Override
@@ -80,10 +73,10 @@ public class VNativeSelect extends VOptionGroupBase implements Field {
public void onChange(ChangeEvent event) {
if (select.isMultipleSelect()) {
- client.updateVariable(id, "selected", getSelectedItems(),
+ client.updateVariable(paintableId, "selected", getSelectedItems(),
isImmediate());
} else {
- client.updateVariable(id, "selected", new String[] { ""
+ client.updateVariable(paintableId, "selected", new String[] { ""
+ getSelectedItem() }, isImmediate());
}
if (firstValueIsTemporaryNullItem) {
@@ -113,5 +106,4 @@ public class VNativeSelect extends VOptionGroupBase implements Field {
public void focus() {
select.setFocus(true);
}
-
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelectPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeSelectPaintable.java
new file mode 100644
index 0000000000..37defb605f
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeSelectPaintable.java
@@ -0,0 +1,21 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+
+public class VNativeSelectPaintable extends VOptionGroupBasePaintable {
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VNativeSelect.class);
+ }
+
+ @Override
+ public VNativeSelect getWidgetForPaintable() {
+ return (VNativeSelect) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java
index 662f195fcd..bf89a01a03 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java
@@ -4,7 +4,6 @@
package com.vaadin.terminal.gwt.client.ui;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -20,7 +19,6 @@ import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.Focusable;
@@ -28,7 +26,6 @@ import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.EventId;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
@@ -40,21 +37,17 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
public static final String CLASSNAME = "v-select-optiongroup";
- private final Panel panel;
+ protected final Panel panel;
private final Map<CheckBox, String> optionsToKeys;
- private boolean sendFocusEvents = false;
- private boolean sendBlurEvents = false;
- private List<HandlerRegistration> focusHandlers = null;
- private List<HandlerRegistration> blurHandlers = null;
+ protected boolean sendFocusEvents = false;
+ protected boolean sendBlurEvents = false;
+ protected List<HandlerRegistration> focusHandlers = null;
+ protected List<HandlerRegistration> blurHandlers = null;
private final LoadHandler iconLoadHandler = new LoadHandler() {
public void onLoad(LoadEvent event) {
- if (BrowserInfo.get().isIE6()) {
- Util.doIE6PngFix((Element) Element.as(event.getNativeEvent()
- .getEventTarget()));
- }
Util.notifyParentOfSizeChange(VOptionGroup.this, true);
}
};
@@ -68,7 +61,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
*/
private boolean blurOccured = false;
- private boolean htmlContentAllowed = false;
+ protected boolean htmlContentAllowed = false;
public VOptionGroup() {
super(CLASSNAME);
@@ -76,43 +69,6 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
optionsToKeys = new HashMap<CheckBox, String>();
}
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- htmlContentAllowed = uidl.hasAttribute(HTML_CONTENT_ALLOWED);
-
- super.updateFromUIDL(uidl, client);
-
- sendFocusEvents = client.hasEventListeners(this, EventId.FOCUS);
- sendBlurEvents = client.hasEventListeners(this, EventId.BLUR);
-
- if (focusHandlers != null) {
- for (HandlerRegistration reg : focusHandlers) {
- reg.removeHandler();
- }
- focusHandlers.clear();
- focusHandlers = null;
-
- for (HandlerRegistration reg : blurHandlers) {
- reg.removeHandler();
- }
- blurHandlers.clear();
- blurHandlers = null;
- }
-
- if (sendFocusEvents || sendBlurEvents) {
- focusHandlers = new ArrayList<HandlerRegistration>();
- blurHandlers = new ArrayList<HandlerRegistration>();
-
- // add focus and blur handlers to checkboxes / radio buttons
- for (Widget wid : panel) {
- if (wid instanceof CheckBox) {
- focusHandlers.add(((CheckBox) wid).addFocusHandler(this));
- blurHandlers.add(((CheckBox) wid).addBlurHandler(this));
- }
- }
- }
- }
-
/*
* Return true if no elements were changed, false otherwise.
*/
@@ -139,7 +95,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
op = new VCheckBox();
op.setHTML(itemHtml);
} else {
- op = new RadioButton(id, itemHtml, true);
+ op = new RadioButton(paintableId, itemHtml, true);
op.setStyleName("v-radiobutton");
}
@@ -180,7 +136,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
} else {
selectedKeys.remove(key);
}
- client.updateVariable(id, "selected", getSelectedItems(),
+ client.updateVariable(paintableId, "selected", getSelectedItems(),
isImmediate());
}
}
@@ -206,7 +162,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
// panel was blurred => fire the event to the server side if
// requested by server side
if (sendFocusEvents) {
- client.updateVariable(id, EventId.FOCUS, "", true);
+ client.updateVariable(paintableId, EventId.FOCUS, "", true);
}
} else {
// blur occured before this focus event
@@ -225,7 +181,8 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
// check whether blurOccured still is true and then send the
// event out to the server
if (blurOccured) {
- client.updateVariable(id, EventId.BLUR, "", true);
+ client.updateVariable(paintableId, EventId.BLUR, "",
+ true);
blurOccured = false;
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java
index 50a9f8cb98..bcd5cc891f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java
@@ -19,35 +19,34 @@ import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
-abstract class VOptionGroupBase extends Composite implements Paintable, Field,
+abstract class VOptionGroupBase extends Composite implements Field,
ClickHandler, ChangeHandler, KeyPressHandler, Focusable {
public static final String CLASSNAME_OPTION = "v-select-option";
protected ApplicationConnection client;
- protected String id;
+ protected String paintableId;
protected Set<String> selectedKeys;
- private boolean immediate;
+ protected boolean immediate;
- private boolean multiselect;
+ protected boolean multiselect;
- private boolean disabled;
+ protected boolean disabled;
- private boolean readonly;
+ protected boolean readonly;
- private int cols = 0;
+ protected int cols = 0;
- private int rows = 0;
+ protected int rows = 0;
- private boolean nullSelectionAllowed = true;
+ protected boolean nullSelectionAllowed = true;
- private boolean nullSelectionItemAvailable = false;
+ protected boolean nullSelectionItemAvailable = false;
/**
* Widget holding the different options (e.g. ListBox or Panel for radio
@@ -58,11 +57,11 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field,
/**
* Panel containing the component
*/
- private final Panel container;
+ protected final Panel container;
- private VTextField newItemField;
+ protected VTextField newItemField;
- private VNativeButton newItemButton;
+ protected VNativeButton newItemButton;
public VOptionGroupBase(String classname) {
container = new FlowPanel();
@@ -122,84 +121,23 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field,
return rows;
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
- id = uidl.getId();
-
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- selectedKeys = uidl.getStringArrayVariableAsSet("selected");
-
- readonly = uidl.getBooleanAttribute("readonly");
- disabled = uidl.getBooleanAttribute("disabled");
- multiselect = "multi".equals(uidl.getStringAttribute("selectmode"));
- immediate = uidl.getBooleanAttribute("immediate");
- nullSelectionAllowed = uidl.getBooleanAttribute("nullselect");
- nullSelectionItemAvailable = uidl.getBooleanAttribute("nullselectitem");
-
- if (uidl.hasAttribute("cols")) {
- cols = uidl.getIntAttribute("cols");
- }
- if (uidl.hasAttribute("rows")) {
- rows = uidl.getIntAttribute("rows");
- }
-
- final UIDL ops = uidl.getChildUIDL(0);
-
- if (getColumns() > 0) {
- container.setWidth(getColumns() + "em");
- if (container != optionsContainer) {
- optionsContainer.setWidth("100%");
- }
- }
-
- buildOptions(ops);
-
- if (uidl.getBooleanAttribute("allownewitem")) {
- if (newItemField == null) {
- newItemButton = new VNativeButton();
- newItemButton.setText("+");
- newItemButton.addClickHandler(this);
- newItemField = new VTextField();
- newItemField.addKeyPressHandler(this);
- }
- newItemField.setEnabled(!disabled && !readonly);
- newItemButton.setEnabled(!disabled && !readonly);
-
- if (newItemField == null || newItemField.getParent() != container) {
- container.add(newItemField);
- container.add(newItemButton);
- final int w = container.getOffsetWidth()
- - newItemButton.getOffsetWidth();
- newItemField.setWidth(Math.max(w, 0) + "px");
- }
- } else if (newItemField != null) {
- container.remove(newItemField);
- container.remove(newItemButton);
- }
-
- setTabIndex(uidl.hasAttribute("tabindex") ? uidl
- .getIntAttribute("tabindex") : 0);
-
- }
-
abstract protected void setTabIndex(int tabIndex);
public void onClick(ClickEvent event) {
if (event.getSource() == newItemButton
&& !newItemField.getText().equals("")) {
- client.updateVariable(id, "newitem", newItemField.getText(), true);
+ client.updateVariable(paintableId, "newitem",
+ newItemField.getText(), true);
newItemField.setText("");
}
}
public void onChange(ChangeEvent event) {
if (multiselect) {
- client.updateVariable(id, "selected", getSelectedItems(), immediate);
+ client.updateVariable(paintableId, "selected", getSelectedItems(),
+ immediate);
} else {
- client.updateVariable(id, "selected", new String[] { ""
+ client.updateVariable(paintableId, "selected", new String[] { ""
+ getSelectedItem() }, immediate);
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBasePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBasePaintable.java
new file mode 100644
index 0000000000..76486ff8a3
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBasePaintable.java
@@ -0,0 +1,103 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public abstract class VOptionGroupBasePaintable extends
+ VAbstractPaintableWidget {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ // Save details
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getId();
+
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ getWidgetForPaintable().selectedKeys = uidl
+ .getStringArrayVariableAsSet("selected");
+
+ getWidgetForPaintable().readonly = uidl.getBooleanAttribute("readonly");
+ getWidgetForPaintable().disabled = uidl.getBooleanAttribute("disabled");
+ getWidgetForPaintable().multiselect = "multi".equals(uidl
+ .getStringAttribute("selectmode"));
+ getWidgetForPaintable().immediate = uidl
+ .getBooleanAttribute("immediate");
+ getWidgetForPaintable().nullSelectionAllowed = uidl
+ .getBooleanAttribute("nullselect");
+ getWidgetForPaintable().nullSelectionItemAvailable = uidl
+ .getBooleanAttribute("nullselectitem");
+
+ if (uidl.hasAttribute("cols")) {
+ getWidgetForPaintable().cols = uidl.getIntAttribute("cols");
+ }
+ if (uidl.hasAttribute("rows")) {
+ getWidgetForPaintable().rows = uidl.getIntAttribute("rows");
+ }
+
+ final UIDL ops = uidl.getChildUIDL(0);
+
+ if (getWidgetForPaintable().getColumns() > 0) {
+ getWidgetForPaintable().container.setWidth(getWidgetForPaintable()
+ .getColumns() + "em");
+ if (getWidgetForPaintable().container != getWidgetForPaintable().optionsContainer) {
+ getWidgetForPaintable().optionsContainer.setWidth("100%");
+ }
+ }
+
+ getWidgetForPaintable().buildOptions(ops);
+
+ if (uidl.getBooleanAttribute("allownewitem")) {
+ if (getWidgetForPaintable().newItemField == null) {
+ getWidgetForPaintable().newItemButton = new VNativeButton();
+ getWidgetForPaintable().newItemButton.setText("+");
+ getWidgetForPaintable().newItemButton
+ .addClickHandler(getWidgetForPaintable());
+ getWidgetForPaintable().newItemField = new VTextField();
+ getWidgetForPaintable().newItemField
+ .addKeyPressHandler(getWidgetForPaintable());
+ }
+ getWidgetForPaintable().newItemField
+ .setEnabled(!getWidgetForPaintable().disabled
+ && !getWidgetForPaintable().readonly);
+ getWidgetForPaintable().newItemButton
+ .setEnabled(!getWidgetForPaintable().disabled
+ && !getWidgetForPaintable().readonly);
+
+ if (getWidgetForPaintable().newItemField == null
+ || getWidgetForPaintable().newItemField.getParent() != getWidgetForPaintable().container) {
+ getWidgetForPaintable().container
+ .add(getWidgetForPaintable().newItemField);
+ getWidgetForPaintable().container
+ .add(getWidgetForPaintable().newItemButton);
+ final int w = getWidgetForPaintable().container
+ .getOffsetWidth()
+ - getWidgetForPaintable().newItemButton
+ .getOffsetWidth();
+ getWidgetForPaintable().newItemField.setWidth(Math.max(w, 0)
+ + "px");
+ }
+ } else if (getWidgetForPaintable().newItemField != null) {
+ getWidgetForPaintable().container
+ .remove(getWidgetForPaintable().newItemField);
+ getWidgetForPaintable().container
+ .remove(getWidgetForPaintable().newItemButton);
+ }
+
+ getWidgetForPaintable().setTabIndex(
+ uidl.hasAttribute("tabindex") ? uidl
+ .getIntAttribute("tabindex") : 0);
+
+ }
+
+ @Override
+ public VOptionGroupBase getWidgetForPaintable() {
+ return (VOptionGroupBase) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupPaintable.java
new file mode 100644
index 0000000000..f4ffc4f0da
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupPaintable.java
@@ -0,0 +1,71 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.EventId;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VOptionGroupPaintable extends VOptionGroupBasePaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().htmlContentAllowed = uidl
+ .hasAttribute(VOptionGroup.HTML_CONTENT_ALLOWED);
+
+ super.updateFromUIDL(uidl, client);
+
+ getWidgetForPaintable().sendFocusEvents = client.hasEventListeners(
+ this, EventId.FOCUS);
+ getWidgetForPaintable().sendBlurEvents = client.hasEventListeners(this,
+ EventId.BLUR);
+
+ if (getWidgetForPaintable().focusHandlers != null) {
+ for (HandlerRegistration reg : getWidgetForPaintable().focusHandlers) {
+ reg.removeHandler();
+ }
+ getWidgetForPaintable().focusHandlers.clear();
+ getWidgetForPaintable().focusHandlers = null;
+
+ for (HandlerRegistration reg : getWidgetForPaintable().blurHandlers) {
+ reg.removeHandler();
+ }
+ getWidgetForPaintable().blurHandlers.clear();
+ getWidgetForPaintable().blurHandlers = null;
+ }
+
+ if (getWidgetForPaintable().sendFocusEvents
+ || getWidgetForPaintable().sendBlurEvents) {
+ getWidgetForPaintable().focusHandlers = new ArrayList<HandlerRegistration>();
+ getWidgetForPaintable().blurHandlers = new ArrayList<HandlerRegistration>();
+
+ // add focus and blur handlers to checkboxes / radio buttons
+ for (Widget wid : getWidgetForPaintable().panel) {
+ if (wid instanceof CheckBox) {
+ getWidgetForPaintable().focusHandlers.add(((CheckBox) wid)
+ .addFocusHandler(getWidgetForPaintable()));
+ getWidgetForPaintable().blurHandlers.add(((CheckBox) wid)
+ .addBlurHandler(getWidgetForPaintable()));
+ }
+ }
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VOptionGroup.class);
+ }
+
+ @Override
+ public VOptionGroup getWidgetForPaintable() {
+ return (VOptionGroup) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
index ecdb171ec4..9f5576dfaf 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
@@ -9,20 +9,14 @@ import java.util.Set;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.event.dom.client.DomEvent.Type;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ValueMap;
import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
@@ -31,21 +25,18 @@ public class VOrderedLayout extends CellBasedLayout {
public static final String CLASSNAME = "v-orderedlayout";
- private int orientation;
-
- // Can be removed once OrderedLayout is removed
- private boolean allowOrientationUpdate = false;
+ int orientation;
/**
* Size of the layout excluding any margins.
*/
- private Size activeLayoutSize = new Size(0, 0);
+ Size activeLayoutSize = new Size(0, 0);
- private boolean isRendering = false;
+ boolean isRendering = false;
private String width = "";
- private boolean sizeHasChangedDuringRendering = false;
+ boolean sizeHasChangedDuringRendering = false;
private ValueMap expandRatios;
@@ -55,24 +46,8 @@ public class VOrderedLayout extends CellBasedLayout {
private ValueMap alignments;
- private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
- this, EventId.LAYOUT_CLICK) {
-
- @Override
- protected Paintable getChildComponent(Element element) {
- return getComponent(element);
- }
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
- };
-
public VOrderedLayout() {
this(CLASSNAME, ORIENTATION_VERTICAL);
- allowOrientationUpdate = true;
}
protected VOrderedLayout(String className, int orientation) {
@@ -86,194 +61,7 @@ public class VOrderedLayout extends CellBasedLayout {
STYLENAME_MARGIN_LEFT = className + "-margin-left";
}
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- isRendering = true;
- super.updateFromUIDL(uidl, client);
-
- // Only non-cached, visible UIDL:s can introduce changes
- if (uidl.getBooleanAttribute("cached")
- || uidl.getBooleanAttribute("invisible")) {
- isRendering = false;
- return;
- }
-
- clickEventHandler.handleEventHandlerRegistration(client);
-
- if (allowOrientationUpdate) {
- handleOrientationUpdate(uidl);
- }
-
- // IStopWatch w = new IStopWatch("OrderedLayout.updateFromUIDL");
-
- ArrayList<Widget> uidlWidgets = new ArrayList<Widget>(
- uidl.getChildCount());
- ArrayList<ChildComponentContainer> relativeSizeComponents = new ArrayList<ChildComponentContainer>();
- ArrayList<UIDL> relativeSizeComponentUIDL = new ArrayList<UIDL>();
-
- int pos = 0;
- for (final Iterator<Object> it = uidl.getChildIterator(); it.hasNext();) {
- final UIDL childUIDL = (UIDL) it.next();
- final Paintable child = client.getPaintable(childUIDL);
- Widget widget = (Widget) child;
-
- // Create container for component
- ChildComponentContainer childComponentContainer = getComponentContainer(widget);
-
- if (childComponentContainer == null) {
- // This is a new component
- childComponentContainer = createChildContainer(widget);
- } else {
- /*
- * The widget may be null if the same paintable has been
- * rendered in a different component container while this has
- * been invisible. Ensure the childComponentContainer has the
- * widget attached. See e.g. #5372
- */
- childComponentContainer.setWidget(widget);
- }
-
- addOrMoveChild(childComponentContainer, pos++);
-
- /*
- * Components which are to be expanded in the same orientation as
- * the layout are rendered later when it is clear how much space
- * they can use
- */
- if (!Util.isCached(childUIDL)) {
- FloatSize relativeSize = Util.parseRelativeSize(childUIDL);
- childComponentContainer.setRelativeSize(relativeSize);
- }
-
- if (childComponentContainer.isComponentRelativeSized(orientation)) {
- relativeSizeComponents.add(childComponentContainer);
- relativeSizeComponentUIDL.add(childUIDL);
- } else {
- if (isDynamicWidth()) {
- childComponentContainer.renderChild(childUIDL, client, -1);
- } else {
- childComponentContainer.renderChild(childUIDL, client,
- activeLayoutSize.getWidth());
- }
- if (sizeHasChangedDuringRendering && Util.isCached(childUIDL)) {
- // notify cached relative sized component about size
- // chance
- client.handleComponentRelativeSize(childComponentContainer
- .getWidget());
- }
- }
-
- uidlWidgets.add(widget);
-
- }
-
- // w.mark("Rendering of "
- // + (uidlWidgets.size() - relativeSizeComponents.size())
- // + " absolute size components done");
-
- /*
- * Remove any children after pos. These are the ones that previously
- * were in the layout but have now been removed
- */
- removeChildrenAfter(pos);
-
- // w.mark("Old children removed");
-
- /* Fetch alignments and expand ratio from UIDL */
- updateAlignmentsAndExpandRatios(uidl, uidlWidgets);
- // w.mark("Alignments and expand ratios updated");
-
- /* Fetch widget sizes from rendered components */
- updateWidgetSizes();
- // w.mark("Widget sizes updated");
-
- recalculateLayout();
- // w.mark("Layout size calculated (" + activeLayoutSize +
- // ") offsetSize: "
- // + getOffsetWidth() + "," + getOffsetHeight());
-
- /* Render relative size components */
- for (int i = 0; i < relativeSizeComponents.size(); i++) {
- ChildComponentContainer childComponentContainer = relativeSizeComponents
- .get(i);
- UIDL childUIDL = relativeSizeComponentUIDL.get(i);
-
- if (isDynamicWidth()) {
- childComponentContainer.renderChild(childUIDL, client, -1);
- } else {
- childComponentContainer.renderChild(childUIDL, client,
- activeLayoutSize.getWidth());
- }
-
- if (Util.isCached(childUIDL)) {
- /*
- * We must update the size of the relative sized component if
- * the expand ratio or something else in the layout changes
- * which affects the size of a relative sized component
- */
- client.handleComponentRelativeSize(childComponentContainer
- .getWidget());
- }
-
- // childComponentContainer.updateWidgetSize();
- }
-
- // w.mark("Rendering of " + (relativeSizeComponents.size())
- // + " relative size components done");
-
- /* Fetch widget sizes for relative size components */
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
-
- /* Update widget size from DOM */
- childComponentContainer.updateWidgetSize();
- }
-
- // w.mark("Widget sizes updated");
-
- /*
- * Components with relative size in main direction may affect the layout
- * size in the other direction
- */
- if ((isHorizontal() && isDynamicHeight())
- || (isVertical() && isDynamicWidth())) {
- layoutSizeMightHaveChanged();
- }
- // w.mark("Layout dimensions updated");
-
- /* Update component spacing */
- updateContainerMargins();
-
- /*
- * Update component sizes for components with relative size in non-main
- * direction
- */
- if (updateRelativeSizesInNonMainDirection()) {
- // Sizes updated - might affect the other dimension so we need to
- // recheck the widget sizes and recalculate layout dimensions
- updateWidgetSizes();
- layoutSizeMightHaveChanged();
- }
- calculateAlignments();
- // w.mark("recalculateComponentSizesAndAlignments done");
-
- setRootSize();
-
- if (BrowserInfo.get().isIE()) {
- /*
- * This should fix the issue with padding not always taken into
- * account for the containers leading to no spacing between
- * elements.
- */
- root.getStyle().setProperty("zoom", "1");
- }
-
- // w.mark("runDescendentsLayout done");
- isRendering = false;
- sizeHasChangedDuringRendering = false;
- }
-
- private void layoutSizeMightHaveChanged() {
+ void layoutSizeMightHaveChanged() {
Size oldSize = new Size(activeLayoutSize.getWidth(),
activeLayoutSize.getHeight());
calculateLayoutDimensions();
@@ -286,7 +74,7 @@ public class VOrderedLayout extends CellBasedLayout {
}
}
- private void updateWidgetSizes() {
+ void updateWidgetSizes() {
for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
.values()) {
@@ -297,7 +85,7 @@ public class VOrderedLayout extends CellBasedLayout {
}
}
- private void recalculateLayout() {
+ void recalculateLayout() {
/* Calculate space for relative size components */
int spaceForExpansion = calculateLayoutDimensions();
@@ -338,30 +126,13 @@ public class VOrderedLayout extends CellBasedLayout {
}
- private void handleOrientationUpdate(UIDL uidl) {
- int newOrientation = ORIENTATION_VERTICAL;
- if ("horizontal".equals(uidl.getStringAttribute("orientation"))) {
- newOrientation = ORIENTATION_HORIZONTAL;
- }
-
- if (orientation != newOrientation) {
- orientation = newOrientation;
-
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
- childComponentContainer.setOrientation(orientation);
- }
- }
-
- }
-
/**
* Updated components with relative height in horizontal layouts and
* components with relative width in vertical layouts. This is only needed
* if the height (horizontal layout) or width (vertical layout) has not been
* specified.
*/
- private boolean updateRelativeSizesInNonMainDirection() {
+ boolean updateRelativeSizesInNonMainDirection() {
int updateDirection = 1 - orientation;
if ((updateDirection == ORIENTATION_HORIZONTAL && !isDynamicWidth())
|| (updateDirection == ORIENTATION_VERTICAL && !isDynamicHeight())) {
@@ -466,7 +237,7 @@ public class VOrderedLayout extends CellBasedLayout {
return widgetWidth;
}
- private void calculateAlignments() {
+ void calculateAlignments() {
int w = 0;
int h = 0;
@@ -674,7 +445,7 @@ public class VOrderedLayout extends CellBasedLayout {
* Updates the spacing between components. Needs to be done only when
* components are added/removed.
*/
- private void updateContainerMargins() {
+ void updateContainerMargins() {
ChildComponentContainer firstChildComponent = getFirstChildComponentContainer();
if (firstChildComponent != null) {
firstChildComponent.setMarginLeft(0);
@@ -695,15 +466,15 @@ public class VOrderedLayout extends CellBasedLayout {
}
}
- private boolean isHorizontal() {
+ boolean isHorizontal() {
return orientation == ORIENTATION_HORIZONTAL;
}
- private boolean isVertical() {
+ boolean isVertical() {
return orientation == ORIENTATION_VERTICAL;
}
- private ChildComponentContainer createChildContainer(Widget child) {
+ ChildComponentContainer createChildContainer(VPaintableWidget child) {
// Create a container DIV for the child
ChildComponentContainer childComponent = new ChildComponentContainer(
@@ -781,15 +552,15 @@ public class VOrderedLayout extends CellBasedLayout {
setRootSize();
}
- private void setRootSize() {
+ void setRootSize() {
root.getStyle().setPropertyPx("width", activeLayoutSize.getWidth());
root.getStyle().setPropertyPx("height", activeLayoutSize.getHeight());
}
- public boolean requestLayout(Set<Paintable> children) {
- for (Paintable p : children) {
+ public boolean requestLayout(Set<Widget> children) {
+ for (Widget p : children) {
/* Update widget size from DOM */
- ChildComponentContainer componentContainer = getComponentContainer((Widget) p);
+ ChildComponentContainer componentContainer = getComponentContainer(p);
// This should no longer be needed (after #2563)
// if (isDynamicWidth()) {
// componentContainer.setUnlimitedContainerWidth();
@@ -898,7 +669,7 @@ public class VOrderedLayout extends CellBasedLayout {
for (int i = 0; i < renderedWidgets.size(); i++) {
Widget widget = renderedWidgets.get(i);
- String pid = client.getPid(widget.getElement());
+ String pid = VPaintableMap.get(client).getPid(widget);
ChildComponentContainer container = getComponentContainer(widget);
@@ -940,18 +711,6 @@ public class VOrderedLayout extends CellBasedLayout {
}
}
- public void updateCaption(Paintable component, UIDL uidl) {
- ChildComponentContainer componentContainer = getComponentContainer((Widget) component);
- componentContainer.updateCaption(uidl, client);
- if (!isRendering) {
- /*
- * This was a component-only update and the possible size change
- * must be propagated to the layout
- */
- client.captionSizeUpdated(component);
- }
- }
-
/**
* Returns the deepest nested child component which contains "element". The
* child component is also returned if "element" is part of its caption.
@@ -962,8 +721,12 @@ public class VOrderedLayout extends CellBasedLayout {
* @return The Paintable which the element is a part of. Null if the element
* belongs to the layout and not to a child.
*/
- private Paintable getComponent(Element element) {
+ VPaintableWidget getComponent(Element element) {
return Util.getPaintableForElement(client, this, element);
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayoutPaintable.java
new file mode 100644
index 0000000000..5fa4f18efe
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayoutPaintable.java
@@ -0,0 +1,254 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.EventId;
+import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayoutPaintable;
+import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
+
+public abstract class VOrderedLayoutPaintable extends CellBasedLayoutPaintable {
+
+ private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
+ this, EventId.LAYOUT_CLICK) {
+
+ @Override
+ protected VPaintableWidget getChildComponent(Element element) {
+ return getWidgetForPaintable().getComponent(element);
+ }
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ };
+
+ public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
+ Widget widget = paintable.getWidgetForPaintable();
+ ChildComponentContainer componentContainer = getWidgetForPaintable()
+ .getComponentContainer(widget);
+ componentContainer.updateCaption(uidl, getConnection());
+ if (!getWidgetForPaintable().isRendering) {
+ /*
+ * This was a component-only update and the possible size change
+ * must be propagated to the layout
+ */
+ getConnection().captionSizeUpdated(widget);
+ }
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().isRendering = true;
+ super.updateFromUIDL(uidl, client);
+
+ // Only non-cached, visible UIDL:s can introduce changes
+ if (uidl.getBooleanAttribute("cached")
+ || uidl.getBooleanAttribute("invisible")) {
+ getWidgetForPaintable().isRendering = false;
+ return;
+ }
+
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ // IStopWatch w = new IStopWatch("OrderedLayout.updateFromUIDL");
+
+ ArrayList<Widget> uidlWidgets = new ArrayList<Widget>(
+ uidl.getChildCount());
+ ArrayList<ChildComponentContainer> relativeSizeComponents = new ArrayList<ChildComponentContainer>();
+ ArrayList<UIDL> relativeSizeComponentUIDL = new ArrayList<UIDL>();
+
+ int pos = 0;
+ for (final Iterator<Object> it = uidl.getChildIterator(); it.hasNext();) {
+ final UIDL childUIDL = (UIDL) it.next();
+ final VPaintableWidget childPaintable = client
+ .getPaintable(childUIDL);
+ Widget widget = childPaintable.getWidgetForPaintable();
+
+ // Create container for component
+ ChildComponentContainer childComponentContainer = getWidgetForPaintable()
+ .getComponentContainer(widget);
+
+ if (childComponentContainer == null) {
+ // This is a new component
+ childComponentContainer = getWidgetForPaintable()
+ .createChildContainer(childPaintable);
+ } else {
+ /*
+ * The widget may be null if the same paintable has been
+ * rendered in a different component container while this has
+ * been invisible. Ensure the childComponentContainer has the
+ * widget attached. See e.g. #5372
+ */
+ childComponentContainer.setPaintable(childPaintable);
+ }
+
+ getWidgetForPaintable().addOrMoveChild(childComponentContainer,
+ pos++);
+
+ /*
+ * Components which are to be expanded in the same orientation as
+ * the layout are rendered later when it is clear how much space
+ * they can use
+ */
+ if (!Util.isCached(childUIDL)) {
+ FloatSize relativeSize = Util.parseRelativeSize(childUIDL);
+ childComponentContainer.setRelativeSize(relativeSize);
+ }
+
+ if (childComponentContainer
+ .isComponentRelativeSized(getWidgetForPaintable().orientation)) {
+ relativeSizeComponents.add(childComponentContainer);
+ relativeSizeComponentUIDL.add(childUIDL);
+ } else {
+ if (getWidgetForPaintable().isDynamicWidth()) {
+ childComponentContainer.renderChild(childUIDL, client, -1);
+ } else {
+ childComponentContainer
+ .renderChild(childUIDL, client,
+ getWidgetForPaintable().activeLayoutSize
+ .getWidth());
+ }
+ if (getWidgetForPaintable().sizeHasChangedDuringRendering
+ && Util.isCached(childUIDL)) {
+ // notify cached relative sized component about size
+ // chance
+ client.handleComponentRelativeSize(childComponentContainer
+ .getWidget());
+ }
+ }
+
+ uidlWidgets.add(widget);
+
+ }
+
+ // w.mark("Rendering of "
+ // + (uidlWidgets.size() - relativeSizeComponents.size())
+ // + " absolute size components done");
+
+ /*
+ * Remove any children after pos. These are the ones that previously
+ * were in the layout but have now been removed
+ */
+ getWidgetForPaintable().removeChildrenAfter(pos);
+
+ // w.mark("Old children removed");
+
+ /* Fetch alignments and expand ratio from UIDL */
+ getWidgetForPaintable().updateAlignmentsAndExpandRatios(uidl,
+ uidlWidgets);
+ // w.mark("Alignments and expand ratios updated");
+
+ /* Fetch widget sizes from rendered components */
+ getWidgetForPaintable().updateWidgetSizes();
+ // w.mark("Widget sizes updated");
+
+ getWidgetForPaintable().recalculateLayout();
+ // w.mark("Layout size calculated (" + activeLayoutSize +
+ // ") offsetSize: "
+ // + getOffsetWidth() + "," + getOffsetHeight());
+
+ /* Render relative size components */
+ for (int i = 0; i < relativeSizeComponents.size(); i++) {
+ ChildComponentContainer childComponentContainer = relativeSizeComponents
+ .get(i);
+ UIDL childUIDL = relativeSizeComponentUIDL.get(i);
+
+ if (getWidgetForPaintable().isDynamicWidth()) {
+ childComponentContainer.renderChild(childUIDL, client, -1);
+ } else {
+ childComponentContainer.renderChild(childUIDL, client,
+ getWidgetForPaintable().activeLayoutSize.getWidth());
+ }
+
+ if (Util.isCached(childUIDL)) {
+ /*
+ * We must update the size of the relative sized component if
+ * the expand ratio or something else in the layout changes
+ * which affects the size of a relative sized component
+ */
+ client.handleComponentRelativeSize(childComponentContainer
+ .getWidget());
+ }
+
+ // childComponentContainer.updateWidgetSize();
+ }
+
+ // w.mark("Rendering of " + (relativeSizeComponents.size())
+ // + " relative size components done");
+
+ /* Fetch widget sizes for relative size components */
+ for (ChildComponentContainer childComponentContainer : getWidgetForPaintable()
+ .getComponentContainers()) {
+
+ /* Update widget size from DOM */
+ childComponentContainer.updateWidgetSize();
+ }
+
+ // w.mark("Widget sizes updated");
+
+ /*
+ * Components with relative size in main direction may affect the layout
+ * size in the other direction
+ */
+ if ((getWidgetForPaintable().isHorizontal() && getWidgetForPaintable()
+ .isDynamicHeight())
+ || (getWidgetForPaintable().isVertical() && getWidgetForPaintable()
+ .isDynamicWidth())) {
+ getWidgetForPaintable().layoutSizeMightHaveChanged();
+ }
+ // w.mark("Layout dimensions updated");
+
+ /* Update component spacing */
+ getWidgetForPaintable().updateContainerMargins();
+
+ /*
+ * Update component sizes for components with relative size in non-main
+ * direction
+ */
+ if (getWidgetForPaintable().updateRelativeSizesInNonMainDirection()) {
+ // Sizes updated - might affect the other dimension so we need to
+ // recheck the widget sizes and recalculate layout dimensions
+ getWidgetForPaintable().updateWidgetSizes();
+ getWidgetForPaintable().layoutSizeMightHaveChanged();
+ }
+ getWidgetForPaintable().calculateAlignments();
+ // w.mark("recalculateComponentSizesAndAlignments done");
+
+ getWidgetForPaintable().setRootSize();
+
+ if (BrowserInfo.get().isIE()) {
+ /*
+ * This should fix the issue with padding not always taken into
+ * account for the containers leading to no spacing between
+ * elements.
+ */
+ getWidgetForPaintable().root.getStyle().setProperty("zoom", "1");
+ }
+
+ // w.mark("runDescendentsLayout done");
+ getWidgetForPaintable().isRendering = false;
+ getWidgetForPaintable().sizeHasChangedDuringRendering = false;
+ }
+
+ @Override
+ protected abstract VOrderedLayout createWidget();
+
+ @Override
+ public VOrderedLayout getWidgetForPaintable() {
+ return (VOrderedLayout) super.getWidgetForPaintable();
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
index 413f30ad06..3d462fb0c6 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
@@ -15,7 +15,6 @@ import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Util;
/**
* In Vaadin UI this Overlay should always be used for all elements that
@@ -162,32 +161,18 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
private static int adjustByRelativeTopBodyMargin() {
if (topFix == -1) {
- boolean ie6OrIe7 = BrowserInfo.get().isIE()
- && BrowserInfo.get().getIEVersion() <= 7;
- topFix = detectRelativeBodyFixes("top", ie6OrIe7);
+ topFix = detectRelativeBodyFixes("top");
}
return topFix;
}
- private native static int detectRelativeBodyFixes(String axis,
- boolean removeClientLeftOrTop)
+ private native static int detectRelativeBodyFixes(String axis)
/*-{
try {
var b = $wnd.document.body;
var cstyle = b.currentStyle ? b.currentStyle : getComputedStyle(b);
if(cstyle && cstyle.position == 'relative') {
- var offset = b.getBoundingClientRect()[axis];
- if (removeClientLeftOrTop) {
- // IE6 and IE7 include the top left border of the client area into the boundingClientRect
- var clientTopOrLeft = 0;
- if (axis == "top")
- clientTopOrLeft = $wnd.document.documentElement.clientTop;
- else
- clientTopOrLeft = $wnd.document.documentElement.clientLeft;
-
- offset -= clientTopOrLeft;
- }
- return offset;
+ return b.getBoundingClientRect()[axis];
}
} catch(e){}
return 0;
@@ -195,9 +180,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
private static int adjustByRelativeLeftBodyMargin() {
if (leftFix == -1) {
- boolean ie6OrIe7 = BrowserInfo.get().isIE()
- && BrowserInfo.get().getIEVersion() <= 7;
- leftFix = detectRelativeBodyFixes("left", ie6OrIe7);
+ leftFix = detectRelativeBodyFixes("left");
}
return leftFix;
@@ -214,13 +197,6 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
updateShadowSizeAndPosition(1.0);
}
}
- Util.runIE7ZeroSizedBodyFix();
- }
-
- @Override
- public void hide(boolean autoClosed) {
- super.hide(autoClosed);
- Util.runIE7ZeroSizedBodyFix();
}
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
index 036f4f0600..354a42c4d5 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
@@ -8,11 +8,8 @@ import java.util.Set;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
-import com.google.gwt.event.dom.client.DomEvent.Type;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.dom.client.TouchStartHandler;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -22,38 +19,38 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
public class VPanel extends SimplePanel implements Container,
ShortcutActionHandlerOwner, Focusable {
- public static final String CLICK_EVENT_IDENTIFIER = "click";
public static final String CLASSNAME = "v-panel";
ApplicationConnection client;
String id;
- private final Element captionNode = DOM.createDiv();
+ final Element captionNode = DOM.createDiv();
private final Element captionText = DOM.createSpan();
private Icon icon;
- private final Element bottomDecoration = DOM.createDiv();
+ final Element bottomDecoration = DOM.createDiv();
- private final Element contentNode = DOM.createDiv();
+ final Element contentNode = DOM.createDiv();
private Element errorIndicatorElement;
private String height;
- private Paintable layout;
+ VPaintableWidget layout;
ShortcutActionHandler shortcutHandler;
@@ -61,9 +58,9 @@ public class VPanel extends SimplePanel implements Container,
private Element geckoCaptionMeter;
- private int scrollTop;
+ int scrollTop;
- private int scrollLeft;
+ int scrollLeft;
private RenderInformation renderInformation = new RenderInformation();
@@ -75,21 +72,12 @@ public class VPanel extends SimplePanel implements Container,
private int captionMarginLeft = -1;
- private boolean rendering;
+ boolean rendering;
private int contentMarginLeft = -1;
private String previousStyleName;
- private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
- CLICK_EVENT_IDENTIFIER) {
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
- };
private TouchScrollDelegate touchScrollDelegate;
public VPanel() {
@@ -156,129 +144,10 @@ public class VPanel extends SimplePanel implements Container,
return contentNode;
}
- private void setCaption(String text) {
+ void setCaption(String text) {
DOM.setInnerHTML(captionText, text);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
- if (!uidl.hasAttribute("cached")) {
-
- // Handle caption displaying and style names, prior generics.
- // Affects size
- // calculations
-
- // Restore default stylenames
- contentNode.setClassName(CLASSNAME + "-content");
- bottomDecoration.setClassName(CLASSNAME + "-deco");
- captionNode.setClassName(CLASSNAME + "-caption");
- boolean hasCaption = false;
- if (uidl.hasAttribute("caption")
- && !uidl.getStringAttribute("caption").equals("")) {
- setCaption(uidl.getStringAttribute("caption"));
- hasCaption = true;
- } else {
- setCaption("");
- captionNode.setClassName(CLASSNAME + "-nocaption");
- }
-
- // Add proper stylenames for all elements. This way we can prevent
- // unwanted CSS selector inheritance.
- if (uidl.hasAttribute("style")) {
- final String[] styles = uidl.getStringAttribute("style").split(
- " ");
- final String captionBaseClass = CLASSNAME
- + (hasCaption ? "-caption" : "-nocaption");
- final String contentBaseClass = CLASSNAME + "-content";
- final String decoBaseClass = CLASSNAME + "-deco";
- String captionClass = captionBaseClass;
- String contentClass = contentBaseClass;
- String decoClass = decoBaseClass;
- for (int i = 0; i < styles.length; i++) {
- captionClass += " " + captionBaseClass + "-" + styles[i];
- contentClass += " " + contentBaseClass + "-" + styles[i];
- decoClass += " " + decoBaseClass + "-" + styles[i];
- }
- captionNode.setClassName(captionClass);
- contentNode.setClassName(contentClass);
- bottomDecoration.setClassName(decoClass);
-
- }
- }
- // Ensure correct implementation
- if (client.updateComponent(this, uidl, false)) {
- rendering = false;
- return;
- }
-
- clickEventHandler.handleEventHandlerRegistration(client);
-
- this.client = client;
- id = uidl.getId();
-
- setIconUri(uidl, client);
-
- handleError(uidl);
-
- // Render content
- final UIDL layoutUidl = uidl.getChildUIDL(0);
- final Paintable newLayout = client.getPaintable(layoutUidl);
- if (newLayout != layout) {
- if (layout != null) {
- client.unregisterPaintable(layout);
- }
- setWidget((Widget) newLayout);
- layout = newLayout;
- }
- layout.updateFromUIDL(layoutUidl, client);
-
- // We may have actions attached to this panel
- if (uidl.getChildCount() > 1) {
- final int cnt = uidl.getChildCount();
- for (int i = 1; i < cnt; i++) {
- UIDL childUidl = uidl.getChildUIDL(i);
- if (childUidl.getTag().equals("actions")) {
- if (shortcutHandler == null) {
- shortcutHandler = new ShortcutActionHandler(id, client);
- }
- shortcutHandler.updateActionMap(childUidl);
- }
- }
- }
-
- if (uidl.hasVariable("scrollTop")
- && uidl.getIntVariable("scrollTop") != scrollTop) {
- scrollTop = uidl.getIntVariable("scrollTop");
- contentNode.setScrollTop(scrollTop);
- // re-read the actual scrollTop in case invalid value was set
- // (scrollTop != 0 when no scrollbar exists, other values would be
- // caught by scroll listener), see #3784
- scrollTop = contentNode.getScrollTop();
- }
-
- if (uidl.hasVariable("scrollLeft")
- && uidl.getIntVariable("scrollLeft") != scrollLeft) {
- scrollLeft = uidl.getIntVariable("scrollLeft");
- contentNode.setScrollLeft(scrollLeft);
- // re-read the actual scrollTop in case invalid value was set
- // (scrollTop != 0 when no scrollbar exists, other values would be
- // caught by scroll listener), see #3784
- scrollLeft = contentNode.getScrollLeft();
- }
-
- // Must be run after scrollTop is set as Webkit overflow fix re-sets the
- // scrollTop
- runHacks(false);
-
- // And apply tab index
- if (uidl.hasVariable("tabindex")) {
- contentNode.setTabIndex(uidl.getIntVariable("tabindex"));
- }
-
- rendering = false;
-
- }
-
@Override
public void setStyleName(String style) {
if (!style.equals(previousStyleName)) {
@@ -288,7 +157,7 @@ public class VPanel extends SimplePanel implements Container,
}
}
- private void handleError(UIDL uidl) {
+ void handleError(UIDL uidl) {
if (uidl.hasAttribute("error")) {
if (errorIndicatorElement == null) {
errorIndicatorElement = DOM.createSpan();
@@ -304,7 +173,7 @@ public class VPanel extends SimplePanel implements Container,
}
}
- private void setIconUri(UIDL uidl, ApplicationConnection client) {
+ void setIconUri(UIDL uidl, ApplicationConnection client) {
final String iconUri = uidl.hasAttribute("icon") ? uidl
.getStringAttribute("icon") : null;
if (iconUri == null) {
@@ -322,60 +191,20 @@ public class VPanel extends SimplePanel implements Container,
}
public void runHacks(boolean runGeckoFix) {
- if (BrowserInfo.get().isIE6() && width != null && !width.equals("")) {
- /*
- * IE6 requires overflow-hidden elements to have a width specified
- * so we calculate the width of the content and caption nodes when
- * no width has been specified.
- */
- /*
- * Fixes #1923 VPanel: Horizontal scrollbar does not appear in IE6
- * with wide content
- */
-
- /*
- * Caption must be shrunk for parent measurements to return correct
- * result in IE6
- */
- DOM.setStyleAttribute(captionNode, "width", "1px");
-
- int parentPadding = Util.measureHorizontalPaddingAndBorder(
- getElement(), 0);
-
- int parentWidthExcludingPadding = getElement().getOffsetWidth()
- - parentPadding;
-
- Util.setWidthExcludingPaddingAndBorder(captionNode,
- parentWidthExcludingPadding - getCaptionMarginLeft(), 26,
- false);
-
- int contentMarginLeft = getContentMarginLeft();
-
- Util.setWidthExcludingPaddingAndBorder(contentNode,
- parentWidthExcludingPadding - contentMarginLeft, 2, false);
-
- }
-
- if ((BrowserInfo.get().isIE() || BrowserInfo.get().isFF2())
- && (width == null || width.equals(""))) {
+ if ((BrowserInfo.get().isIE()) && (width == null || width.equals(""))) {
/*
- * IE and FF2 needs width to be specified for the root DIV so we
- * calculate that from the sizes of the caption and layout
+ * IE (what version??) needs width to be specified for the root DIV
+ * so we calculate that from the sizes of the caption and layout
*/
int captionWidth = captionText.getOffsetWidth()
+ getCaptionMarginLeft() + getCaptionPaddingHorizontal();
- int layoutWidth = ((Widget) layout).getOffsetWidth()
+ int layoutWidth = layout.getWidgetForPaintable().getOffsetWidth()
+ getContainerBorderWidth();
int width = layoutWidth;
if (captionWidth > width) {
width = captionWidth;
}
- if (BrowserInfo.get().isIE7()) {
- Util.setWidthExcludingPaddingAndBorder(captionNode, width
- - getCaptionMarginLeft(), 26, false);
- }
-
super.setWidth(width + "px");
}
@@ -433,7 +262,7 @@ public class VPanel extends SimplePanel implements Container,
}
} else if (captionNode.isOrHasChild(target)) {
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
}
}
@@ -509,7 +338,8 @@ public class VPanel extends SimplePanel implements Container,
if (height.equals("")) {
// Width change may affect height
- Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
+ Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this,
+ this);
}
}
@@ -548,12 +378,12 @@ public class VPanel extends SimplePanel implements Container,
public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
// TODO This is untested as no layouts require this
- if (oldComponent != layout) {
+ if (oldComponent != layout.getWidgetForPaintable()) {
return;
}
setWidget(newComponent);
- layout = (Paintable) newComponent;
+ layout = VPaintableMap.get(client).getPaintable(newComponent);
}
public RenderSpace getAllocatedSpace(Widget child) {
@@ -577,10 +407,10 @@ public class VPanel extends SimplePanel implements Container,
return new RenderSpace(w, h, true);
}
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
// content size change might cause change to its available space
// (scrollbars)
- client.handleComponentRelativeSize((Widget) layout);
+ client.handleComponentRelativeSize(layout.getWidgetForPaintable());
if (height != null && height != "" && width != null && width != "") {
/*
* If the height and width has been specified the child components
@@ -592,10 +422,6 @@ public class VPanel extends SimplePanel implements Container,
return !renderInformation.updateSize(getElement());
}
- public void updateCaption(Paintable component, UIDL uidl) {
- // NOP: layouts caption, errors etc not rendered in Panel
- }
-
@Override
protected void onAttach() {
super.onAttach();
@@ -606,4 +432,8 @@ public class VPanel extends SimplePanel implements Container,
return shortcutHandler;
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPanelPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VPanelPaintable.java
new file mode 100644
index 0000000000..c401c6db84
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPanelPaintable.java
@@ -0,0 +1,175 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VPanelPaintable extends VAbstractPaintableWidgetContainer {
+
+ public static final String CLICK_EVENT_IDENTIFIER = "click";
+
+ private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
+ CLICK_EVENT_IDENTIFIER) {
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ };
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+ if (!uidl.hasAttribute("cached")) {
+
+ // Handle caption displaying and style names, prior generics.
+ // Affects size
+ // calculations
+
+ // Restore default stylenames
+ getWidgetForPaintable().contentNode.setClassName(VPanel.CLASSNAME
+ + "-content");
+ getWidgetForPaintable().bottomDecoration
+ .setClassName(VPanel.CLASSNAME + "-deco");
+ getWidgetForPaintable().captionNode.setClassName(VPanel.CLASSNAME
+ + "-caption");
+ boolean hasCaption = false;
+ if (uidl.hasAttribute("caption")
+ && !uidl.getStringAttribute("caption").equals("")) {
+ getWidgetForPaintable().setCaption(
+ uidl.getStringAttribute("caption"));
+ hasCaption = true;
+ } else {
+ getWidgetForPaintable().setCaption("");
+ getWidgetForPaintable().captionNode
+ .setClassName(VPanel.CLASSNAME + "-nocaption");
+ }
+
+ // Add proper stylenames for all elements. This way we can prevent
+ // unwanted CSS selector inheritance.
+ if (uidl.hasAttribute("style")) {
+ final String[] styles = uidl.getStringAttribute("style").split(
+ " ");
+ final String captionBaseClass = VPanel.CLASSNAME
+ + (hasCaption ? "-caption" : "-nocaption");
+ final String contentBaseClass = VPanel.CLASSNAME + "-content";
+ final String decoBaseClass = VPanel.CLASSNAME + "-deco";
+ String captionClass = captionBaseClass;
+ String contentClass = contentBaseClass;
+ String decoClass = decoBaseClass;
+ for (int i = 0; i < styles.length; i++) {
+ captionClass += " " + captionBaseClass + "-" + styles[i];
+ contentClass += " " + contentBaseClass + "-" + styles[i];
+ decoClass += " " + decoBaseClass + "-" + styles[i];
+ }
+ getWidgetForPaintable().captionNode.setClassName(captionClass);
+ getWidgetForPaintable().contentNode.setClassName(contentClass);
+ getWidgetForPaintable().bottomDecoration
+ .setClassName(decoClass);
+
+ }
+ }
+ // Ensure correct implementation
+ if (client.updateComponent(this, uidl, false)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().id = uidl.getId();
+
+ getWidgetForPaintable().setIconUri(uidl, client);
+
+ getWidgetForPaintable().handleError(uidl);
+
+ // Render content
+ final UIDL layoutUidl = uidl.getChildUIDL(0);
+ final VPaintableWidget newLayout = client.getPaintable(layoutUidl);
+ if (newLayout != getWidgetForPaintable().layout) {
+ if (getWidgetForPaintable().layout != null) {
+ client.unregisterPaintable(getWidgetForPaintable().layout);
+ }
+ getWidgetForPaintable()
+ .setWidget(newLayout.getWidgetForPaintable());
+ getWidgetForPaintable().layout = newLayout;
+ }
+ getWidgetForPaintable().layout.updateFromUIDL(layoutUidl, client);
+
+ // We may have actions attached to this panel
+ if (uidl.getChildCount() > 1) {
+ final int cnt = uidl.getChildCount();
+ for (int i = 1; i < cnt; i++) {
+ UIDL childUidl = uidl.getChildUIDL(i);
+ if (childUidl.getTag().equals("actions")) {
+ if (getWidgetForPaintable().shortcutHandler == null) {
+ getWidgetForPaintable().shortcutHandler = new ShortcutActionHandler(
+ getId(), client);
+ }
+ getWidgetForPaintable().shortcutHandler
+ .updateActionMap(childUidl);
+ }
+ }
+ }
+
+ if (uidl.hasVariable("scrollTop")
+ && uidl.getIntVariable("scrollTop") != getWidgetForPaintable().scrollTop) {
+ getWidgetForPaintable().scrollTop = uidl
+ .getIntVariable("scrollTop");
+ getWidgetForPaintable().contentNode
+ .setScrollTop(getWidgetForPaintable().scrollTop);
+ // re-read the actual scrollTop in case invalid value was set
+ // (scrollTop != 0 when no scrollbar exists, other values would be
+ // caught by scroll listener), see #3784
+ getWidgetForPaintable().scrollTop = getWidgetForPaintable().contentNode
+ .getScrollTop();
+ }
+
+ if (uidl.hasVariable("scrollLeft")
+ && uidl.getIntVariable("scrollLeft") != getWidgetForPaintable().scrollLeft) {
+ getWidgetForPaintable().scrollLeft = uidl
+ .getIntVariable("scrollLeft");
+ getWidgetForPaintable().contentNode
+ .setScrollLeft(getWidgetForPaintable().scrollLeft);
+ // re-read the actual scrollTop in case invalid value was set
+ // (scrollTop != 0 when no scrollbar exists, other values would be
+ // caught by scroll listener), see #3784
+ getWidgetForPaintable().scrollLeft = getWidgetForPaintable().contentNode
+ .getScrollLeft();
+ }
+
+ // Must be run after scrollTop is set as Webkit overflow fix re-sets the
+ // scrollTop
+ getWidgetForPaintable().runHacks(false);
+
+ // And apply tab index
+ if (uidl.hasVariable("tabindex")) {
+ getWidgetForPaintable().contentNode.setTabIndex(uidl
+ .getIntVariable("tabindex"));
+ }
+
+ getWidgetForPaintable().rendering = false;
+
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ // NOP: layouts caption, errors etc not rendered in Panel
+ }
+
+ @Override
+ public VPanel getWidgetForPaintable() {
+ return (VPanel) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VPanel.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPasswordFieldPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VPasswordFieldPaintable.java
new file mode 100644
index 0000000000..98be1250a3
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPasswordFieldPaintable.java
@@ -0,0 +1,28 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VPasswordFieldPaintable extends VTextFieldPaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ super.updateFromUIDL(uidl, client);
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VPasswordField.class);
+ }
+
+ @Override
+ public VPasswordField getWidgetForPaintable() {
+ return (VPasswordField) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
index 8bf2f6bfbf..1c0b937e05 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
@@ -21,16 +21,10 @@ import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.DateTimeService;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VConsole;
-import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener;
import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener;
import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener;
-import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener;
/**
* Represents a date selection component with a text field and a popup date
@@ -42,19 +36,19 @@ import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener;
* <code>setCalendarPanel(VCalendarPanel panel)</code> method.
*
*/
-public class VPopupCalendar extends VTextualDate implements Paintable, Field,
+public class VPopupCalendar extends VTextualDate implements Field,
ClickHandler, CloseHandler<PopupPanel>, SubPartAware {
- private static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME
+ protected static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME
+ "-popup";
- private final Button calendarToggle;
+ protected final Button calendarToggle;
- private VCalendarPanel calendar;
+ protected VCalendarPanel calendar;
- private final VOverlay popup;
+ protected final VOverlay popup;
private boolean open = false;
- private boolean parsable = true;
+ protected boolean parsable = true;
public VPopupCalendar() {
super();
@@ -105,7 +99,7 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
}
@SuppressWarnings("deprecation")
- private void updateValue(Date newDate) {
+ protected void updateValue(Date newDate) {
Date currentDate = getCurrentDate();
if (currentDate == null || newDate.getTime() != currentDate.getTime()) {
setCurrentDate((Date) newDate.clone());
@@ -126,14 +120,6 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
if (getCurrentResolution() > RESOLUTION_MIN) {
getClient().updateVariable(getId(), "sec",
newDate.getSeconds(), false);
- if (getCurrentResolution() == RESOLUTION_MSEC) {
- getClient().updateVariable(
- getId(),
- "msec",
- DateTimeService
- .getMilliseconds(newDate),
- false);
- }
}
}
}
@@ -149,96 +135,6 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
* (non-Javadoc)
*
* @see
- * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin
- * .terminal.gwt.client.UIDL,
- * com.vaadin.terminal.gwt.client.ApplicationConnection)
- */
- @Override
- @SuppressWarnings("deprecation")
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- boolean lastReadOnlyState = readonly;
- boolean lastEnabledState = isEnabled();
-
- parsable = uidl.getBooleanAttribute("parsable");
-
- super.updateFromUIDL(uidl, client);
-
- String popupStyleNames = ApplicationConnection.getStyleName(
- POPUP_PRIMARY_STYLE_NAME, uidl, false);
- popupStyleNames += " " + VDateField.CLASSNAME + "-"
- + resolutionToString(currentResolution);
- popup.setStyleName(popupStyleNames);
-
- calendar.setDateTimeService(getDateTimeService());
- calendar.setShowISOWeekNumbers(isShowISOWeekNumbers());
- if (calendar.getResolution() != currentResolution) {
- calendar.setResolution(currentResolution);
- if (calendar.getDate() != null) {
- calendar.setDate((Date) getCurrentDate().clone());
- // force re-render when changing resolution only
- calendar.renderCalendar();
- }
- }
- calendarToggle.setEnabled(enabled);
-
- if (currentResolution <= RESOLUTION_MONTH) {
- calendar.setFocusChangeListener(new FocusChangeListener() {
- public void focusChanged(Date date) {
- updateValue(date);
- buildDate();
- Date date2 = calendar.getDate();
- date2.setYear(date.getYear());
- date2.setMonth(date.getMonth());
- }
- });
- } else {
- calendar.setFocusChangeListener(null);
- }
-
- if (currentResolution > RESOLUTION_DAY) {
- calendar.setTimeChangeListener(new TimeChangeListener() {
- public void changed(int hour, int min, int sec, int msec) {
- Date d = getDate();
- if (d == null) {
- // date currently null, use the value from calendarPanel
- // (~ client time at the init of the widget)
- d = (Date) calendar.getDate().clone();
- }
- d.setHours(hour);
- d.setMinutes(min);
- d.setSeconds(sec);
- DateTimeService.setMilliseconds(d, msec);
-
- // Always update time changes to the server
- updateValue(d);
-
- // Update text field
- buildDate();
- }
- });
- }
-
- if (readonly) {
- calendarToggle.addStyleName(CLASSNAME + "-button-readonly");
- } else {
- calendarToggle.removeStyleName(CLASSNAME + "-button-readonly");
- }
-
- if (lastReadOnlyState != readonly || lastEnabledState != isEnabled()) {
- // Enabled or readonly state changed. Differences in theming might
- // affect the width (for instance if the popup button is hidden) so
- // we have to recalculate the width (IF the width of the field is
- // fixed)
- updateWidth();
- }
-
- calendarToggle.setEnabled(true);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
* com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String)
*/
@Override
@@ -276,7 +172,7 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
int l = calendarToggle.getAbsoluteLeft();
// Add a little extra space to the right to avoid
- // problems with IE6/IE7 scrollbars and to make it look
+ // problems with IE7 scrollbars and to make it look
// nicer.
int extraSpace = 30;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendarPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendarPaintable.java
new file mode 100644
index 0000000000..96e966a993
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendarPaintable.java
@@ -0,0 +1,138 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.DateTimeService;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener;
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener;
+
+public class VPopupCalendarPaintable extends VTextualDatePaintable {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin
+ * .terminal.gwt.client.UIDL,
+ * com.vaadin.terminal.gwt.client.ApplicationConnection)
+ */
+ @Override
+ @SuppressWarnings("deprecation")
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ boolean lastReadOnlyState = getWidgetForPaintable().readonly;
+ boolean lastEnabledState = getWidgetForPaintable().isEnabled();
+
+ getWidgetForPaintable().parsable = uidl.getBooleanAttribute("parsable");
+
+ super.updateFromUIDL(uidl, client);
+
+ String popupStyleNames = ApplicationConnection.getStyleName(
+ VPopupCalendar.POPUP_PRIMARY_STYLE_NAME, uidl, false);
+ popupStyleNames += " "
+ + VDateField.CLASSNAME
+ + "-"
+ + VPopupCalendar
+ .resolutionToString(getWidgetForPaintable().currentResolution);
+ getWidgetForPaintable().popup.setStyleName(popupStyleNames);
+
+ getWidgetForPaintable().calendar
+ .setDateTimeService(getWidgetForPaintable()
+ .getDateTimeService());
+ getWidgetForPaintable().calendar
+ .setShowISOWeekNumbers(getWidgetForPaintable()
+ .isShowISOWeekNumbers());
+ if (getWidgetForPaintable().calendar.getResolution() != getWidgetForPaintable().currentResolution) {
+ getWidgetForPaintable().calendar
+ .setResolution(getWidgetForPaintable().currentResolution);
+ if (getWidgetForPaintable().calendar.getDate() != null) {
+ getWidgetForPaintable().calendar
+ .setDate((Date) getWidgetForPaintable()
+ .getCurrentDate().clone());
+ // force re-render when changing resolution only
+ getWidgetForPaintable().calendar.renderCalendar();
+ }
+ }
+ getWidgetForPaintable().calendarToggle
+ .setEnabled(getWidgetForPaintable().enabled);
+
+ if (getWidgetForPaintable().currentResolution <= VPopupCalendar.RESOLUTION_MONTH) {
+ getWidgetForPaintable().calendar
+ .setFocusChangeListener(new FocusChangeListener() {
+ public void focusChanged(Date date) {
+ getWidgetForPaintable().updateValue(date);
+ getWidgetForPaintable().buildDate();
+ Date date2 = getWidgetForPaintable().calendar
+ .getDate();
+ date2.setYear(date.getYear());
+ date2.setMonth(date.getMonth());
+ }
+ });
+ } else {
+ getWidgetForPaintable().calendar.setFocusChangeListener(null);
+ }
+
+ if (getWidgetForPaintable().currentResolution > VPopupCalendar.RESOLUTION_DAY) {
+ getWidgetForPaintable().calendar
+ .setTimeChangeListener(new TimeChangeListener() {
+ public void changed(int hour, int min, int sec, int msec) {
+ Date d = getWidgetForPaintable().getDate();
+ if (d == null) {
+ // date currently null, use the value from
+ // calendarPanel
+ // (~ client time at the init of the widget)
+ d = (Date) getWidgetForPaintable().calendar
+ .getDate().clone();
+ }
+ d.setHours(hour);
+ d.setMinutes(min);
+ d.setSeconds(sec);
+ DateTimeService.setMilliseconds(d, msec);
+
+ // Always update time changes to the server
+ getWidgetForPaintable().updateValue(d);
+
+ // Update text field
+ getWidgetForPaintable().buildDate();
+ }
+ });
+ }
+
+ if (getWidgetForPaintable().readonly) {
+ getWidgetForPaintable().calendarToggle
+ .addStyleName(VPopupCalendar.CLASSNAME + "-button-readonly");
+ } else {
+ getWidgetForPaintable().calendarToggle
+ .removeStyleName(VPopupCalendar.CLASSNAME
+ + "-button-readonly");
+ }
+
+ if (lastReadOnlyState != getWidgetForPaintable().readonly
+ || lastEnabledState != getWidgetForPaintable().isEnabled()) {
+ // Enabled or readonly state changed. Differences in theming might
+ // affect the width (for instance if the popup button is hidden) so
+ // we have to recalculate the width (IF the width of the field is
+ // fixed)
+ getWidgetForPaintable().updateWidth();
+ }
+
+ getWidgetForPaintable().calendarToggle.setEnabled(true);
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VPopupCalendar.class);
+ }
+
+ @Override
+ public VPopupCalendar getWidgetForPaintable() {
+ return (VPopupCalendar) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java
index 907e11ac2d..34bf0ca619 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java
@@ -25,13 +25,12 @@ import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VCaption;
import com.vaadin.terminal.gwt.client.VCaptionWrapper;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.VTooltip;
import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea;
@@ -40,13 +39,13 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
public static final String CLASSNAME = "v-popupview";
/** For server-client communication */
- private String uidlId;
- private ApplicationConnection client;
+ String uidlId;
+ ApplicationConnection client;
/** This variable helps to communicate popup visibility to the server */
- private boolean hostPopupVisible;
+ boolean hostPopupVisible;
- private final CustomPopup popup;
+ final CustomPopup popup;
private final Label loading = new Label();
/**
@@ -82,61 +81,6 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
}
/**
- *
- *
- * @see com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal.gwt.client.UIDL,
- * com.vaadin.terminal.gwt.client.ApplicationConnection)
- */
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // This call should be made first. Ensure correct implementation,
- // and don't let the containing layout manage caption.
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
- // These are for future server connections
- this.client = client;
- uidlId = uidl.getId();
-
- hostPopupVisible = uidl.getBooleanVariable("popupVisibility");
-
- setHTML(uidl.getStringAttribute("html"));
-
- if (uidl.hasAttribute("hideOnMouseOut")) {
- popup.setHideOnMouseOut(uidl.getBooleanAttribute("hideOnMouseOut"));
- }
-
- // Render the popup if visible and show it.
- if (hostPopupVisible) {
- UIDL popupUIDL = uidl.getChildUIDL(0);
-
- // showPopupOnTop(popup, hostReference);
- preparePopup(popup);
- popup.updateFromUIDL(popupUIDL, client);
- if (uidl.hasAttribute("style")) {
- final String[] styles = uidl.getStringAttribute("style").split(
- " ");
- final StringBuffer styleBuf = new StringBuffer();
- final String primaryName = popup.getStylePrimaryName();
- styleBuf.append(primaryName);
- for (int i = 0; i < styles.length; i++) {
- styleBuf.append(" ");
- styleBuf.append(primaryName);
- styleBuf.append("-");
- styleBuf.append(styles[i]);
- }
- popup.setStyleName(styleBuf.toString());
- } else {
- popup.setStyleName(popup.getStylePrimaryName());
- }
- showPopup(popup);
-
- // The popup shouldn't be visible, try to hide it.
- } else {
- popup.hide();
- }
- }// updateFromUIDL
-
- /**
* Update popup visibility to server
*
* @param visibility
@@ -149,7 +93,7 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
}
}
- private void preparePopup(final CustomPopup popup) {
+ void preparePopup(final CustomPopup popup) {
popup.setVisible(false);
popup.show();
}
@@ -230,9 +174,9 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
*/
protected class CustomPopup extends VOverlay {
- private Paintable popupComponentPaintable = null;
- private Widget popupComponentWidget = null;
- private VCaptionWrapper captionWrapper = null;
+ private VPaintableWidget popupComponentPaintable = null;
+ Widget popupComponentWidget = null;
+ VCaptionWrapper captionWrapper = null;
private boolean hasHadMouseOver = false;
private boolean hideOnMouseOut = true;
@@ -346,15 +290,13 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- Paintable newPopupComponent = client.getPaintable(uidl
+ VPaintableWidget newPopupComponent = client.getPaintable(uidl
.getChildUIDL(0));
if (newPopupComponent != popupComponentPaintable) {
-
- setWidget((Widget) newPopupComponent);
-
- popupComponentWidget = (Widget) newPopupComponent;
-
+ Widget newWidget = newPopupComponent.getWidgetForPaintable();
+ setWidget(newWidget);
+ popupComponentWidget = newWidget;
popupComponentPaintable = newPopupComponent;
}
@@ -443,35 +385,16 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
popup.popupComponentWidget = newComponent;
}
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
popup.updateShadowSizeAndPosition();
return true;
}
- public void updateCaption(Paintable component, UIDL uidl) {
- if (VCaption.isNeeded(uidl)) {
- if (popup.captionWrapper != null) {
- popup.captionWrapper.updateCaption(uidl);
- } else {
- popup.captionWrapper = new VCaptionWrapper(component, client);
- popup.setWidget(popup.captionWrapper);
- popup.captionWrapper.updateCaption(uidl);
- }
- } else {
- if (popup.captionWrapper != null) {
- popup.setWidget(popup.popupComponentWidget);
- }
- }
-
- popup.popupComponentWidget = (Widget) component;
- popup.popupComponentPaintable = component;
- }
-
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
}
@@ -501,4 +424,8 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
};
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}// class VPopupView
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupViewPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupViewPaintable.java
new file mode 100644
index 0000000000..e2399bafed
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupViewPaintable.java
@@ -0,0 +1,104 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.VCaptionWrapper;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VPopupViewPaintable extends VAbstractPaintableWidgetContainer {
+
+ /**
+ *
+ *
+ * @see com.vaadin.terminal.gwt.client.VPaintableWidget#updateFromUIDL(com.vaadin.terminal.gwt.client.UIDL,
+ * com.vaadin.terminal.gwt.client.ApplicationConnection)
+ */
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // This call should be made first. Ensure correct implementation,
+ // and don't let the containing layout manage caption.
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+ // These are for future server connections
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().uidlId = uidl.getId();
+
+ getWidgetForPaintable().hostPopupVisible = uidl
+ .getBooleanVariable("popupVisibility");
+
+ getWidgetForPaintable().setHTML(uidl.getStringAttribute("html"));
+
+ if (uidl.hasAttribute("hideOnMouseOut")) {
+ getWidgetForPaintable().popup.setHideOnMouseOut(uidl
+ .getBooleanAttribute("hideOnMouseOut"));
+ }
+
+ // Render the popup if visible and show it.
+ if (getWidgetForPaintable().hostPopupVisible) {
+ UIDL popupUIDL = uidl.getChildUIDL(0);
+
+ // showPopupOnTop(popup, hostReference);
+ getWidgetForPaintable().preparePopup(getWidgetForPaintable().popup);
+ getWidgetForPaintable().popup.updateFromUIDL(popupUIDL, client);
+ if (uidl.hasAttribute("style")) {
+ final String[] styles = uidl.getStringAttribute("style").split(
+ " ");
+ final StringBuffer styleBuf = new StringBuffer();
+ final String primaryName = getWidgetForPaintable().popup
+ .getStylePrimaryName();
+ styleBuf.append(primaryName);
+ for (int i = 0; i < styles.length; i++) {
+ styleBuf.append(" ");
+ styleBuf.append(primaryName);
+ styleBuf.append("-");
+ styleBuf.append(styles[i]);
+ }
+ getWidgetForPaintable().popup.setStyleName(styleBuf.toString());
+ } else {
+ getWidgetForPaintable().popup
+ .setStyleName(getWidgetForPaintable().popup
+ .getStylePrimaryName());
+ }
+ getWidgetForPaintable().showPopup(getWidgetForPaintable().popup);
+
+ // The popup shouldn't be visible, try to hide it.
+ } else {
+ getWidgetForPaintable().popup.hide();
+ }
+ }// updateFromUIDL
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ if (VCaption.isNeeded(uidl)) {
+ if (getWidgetForPaintable().popup.captionWrapper != null) {
+ getWidgetForPaintable().popup.captionWrapper
+ .updateCaption(uidl);
+ } else {
+ getWidgetForPaintable().popup.captionWrapper = new VCaptionWrapper(
+ component, getConnection());
+ getWidgetForPaintable().popup
+ .setWidget(getWidgetForPaintable().popup.captionWrapper);
+ getWidgetForPaintable().popup.captionWrapper
+ .updateCaption(uidl);
+ }
+ } else {
+ if (getWidgetForPaintable().popup.captionWrapper != null) {
+ getWidgetForPaintable().popup
+ .setWidget(getWidgetForPaintable().popup.popupComponentWidget);
+ }
+ }
+ }
+
+ @Override
+ public VPopupView getWidgetForPaintable() {
+ return (VPopupView) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VPopupView.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java b/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java
index d5eac590ad..cff6bf89bd 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java
@@ -9,20 +9,18 @@ import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-public class VProgressIndicator extends Widget implements Paintable {
+public class VProgressIndicator extends Widget {
- private static final String CLASSNAME = "v-progressindicator";
+ public static final String CLASSNAME = "v-progressindicator";
Element wrapper = DOM.createDiv();
Element indicator = DOM.createDiv();
- private ApplicationConnection client;
- private final Poller poller;
- private boolean indeterminate = false;
+ protected ApplicationConnection client;
+ protected final Poller poller;
+ protected boolean indeterminate = false;
private boolean pollerSuspendedDueDetach;
- private int interval;
+ protected int interval;
public VProgressIndicator() {
setElement(DOM.createDiv());
@@ -34,38 +32,6 @@ public class VProgressIndicator extends Widget implements Paintable {
poller = new Poller();
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
- if (!uidl.getBooleanAttribute("cached")) {
- poller.cancel();
- }
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- indeterminate = uidl.getBooleanAttribute("indeterminate");
-
- if (indeterminate) {
- String basename = CLASSNAME + "-indeterminate";
- VProgressIndicator.setStyleName(getElement(), basename, true);
- VProgressIndicator.setStyleName(getElement(), basename
- + "-disabled", uidl.getBooleanAttribute("disabled"));
- } else {
- try {
- final float f = Float.parseFloat(uidl
- .getStringAttribute("state"));
- final int size = Math.round(100 * f);
- DOM.setStyleAttribute(indicator, "width", size + "%");
- } catch (final Exception e) {
- }
- }
-
- if (!uidl.getBooleanAttribute("disabled")) {
- interval = uidl.getIntAttribute("pollinginterval");
- poller.scheduleRepeating(interval);
- }
- }
-
@Override
protected void onAttach() {
super.onAttach();
@@ -102,5 +68,4 @@ public class VProgressIndicator extends Widget implements Paintable {
}
}
-
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicatorPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicatorPaintable.java
new file mode 100644
index 0000000000..39ffe1ad96
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicatorPaintable.java
@@ -0,0 +1,65 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VProgressIndicatorPaintable extends VAbstractPaintableWidget {
+
+ 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
+ getWidgetForPaintable().client = client;
+
+ getWidgetForPaintable().indeterminate = uidl
+ .getBooleanAttribute("indeterminate");
+
+ if (getWidgetForPaintable().indeterminate) {
+ String basename = VProgressIndicator.CLASSNAME + "-indeterminate";
+ getWidgetForPaintable().addStyleName(basename);
+ if (uidl.getBooleanAttribute("disabled")) {
+ getWidgetForPaintable().addStyleName(basename + "-disabled");
+ } else {
+ getWidgetForPaintable().removeStyleName(basename + "-disabled");
+ }
+ } else {
+ try {
+ final float f = Float.parseFloat(uidl
+ .getStringAttribute("state"));
+ final int size = Math.round(100 * f);
+ DOM.setStyleAttribute(getWidgetForPaintable().indicator,
+ "width", size + "%");
+ } catch (final Exception e) {
+ }
+ }
+
+ if (!uidl.getBooleanAttribute("disabled")) {
+ getWidgetForPaintable().interval = uidl
+ .getIntAttribute("pollinginterval");
+ getWidgetForPaintable().poller
+ .scheduleRepeating(getWidgetForPaintable().interval);
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VProgressIndicator.class);
+ }
+
+ @Override
+ public VProgressIndicator getWidgetForPaintable() {
+ return (VProgressIndicator) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
index f7d23d4453..24763745e3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
@@ -52,6 +52,7 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.UIObject;
@@ -61,12 +62,13 @@ import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.Focusable;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.TooltipInfo;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.VTooltip;
import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow;
import com.vaadin.terminal.gwt.client.ui.dd.DDUtil;
@@ -77,6 +79,7 @@ import com.vaadin.terminal.gwt.client.ui.dd.VDragEvent;
import com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler;
import com.vaadin.terminal.gwt.client.ui.dd.VTransferable;
import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
+import com.vaadin.terminal.gwt.client.ui.label.VLabel;
/**
* VScrollTable
@@ -101,17 +104,31 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
*
* TODO implement unregistering for child components in Cells
*/
-public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
- VHasDropHandler, FocusHandler, BlurHandler, Focusable, ActionOwner {
+public class VScrollTable extends FlowPanel implements HasWidgets,
+ ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable,
+ ActionOwner {
- public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft";
- public static final String ATTRIBUTE_PAGEBUFFER_LAST = "pb-l";
+ public enum SelectMode {
+ NONE(0), SINGLE(1), MULTI(2);
+ private int id;
+
+ private SelectMode(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+ }
private static final String ROW_HEADER_COLUMN_KEY = "0";
public static final String CLASSNAME = "v-table";
public static final String CLASSNAME_SELECTION_FOCUS = CLASSNAME + "-focus";
+ public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft";
+ public static final String ATTRIBUTE_PAGEBUFFER_LAST = "pb-l";
+
public static final String ITEM_CLICK_EVENT_ID = "itemClick";
public static final String HEADER_CLICK_EVENT_ID = "handleHeaderClick";
public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick";
@@ -160,10 +177,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
protected ApplicationConnection client;
protected String paintableId;
- private boolean immediate;
+ boolean immediate;
private boolean nullSelectionAllowed = true;
- private int selectMode = Table.SELECT_MODE_NONE;
+ private SelectMode selectMode = SelectMode.NONE;
private final HashSet<String> selectedRowKeys = new HashSet<String>();
@@ -176,15 +193,15 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
/*
* These are used when jumping between pages when pressing Home and End
*/
- private boolean selectLastItemInNextRender = false;
- private boolean selectFirstItemInNextRender = false;
- private boolean focusFirstItemInNextRender = false;
- private boolean focusLastItemInNextRender = false;
+ boolean selectLastItemInNextRender = false;
+ boolean selectFirstItemInNextRender = false;
+ boolean focusFirstItemInNextRender = false;
+ boolean focusLastItemInNextRender = false;
/*
* The currently focused row
*/
- private VScrollTableRow focusedRow;
+ VScrollTableRow focusedRow;
/*
* Helper to store selection range start in when using the keyboard
@@ -195,7 +212,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* Flag for notifying when the selection has changed and should be sent to
* the server
*/
- private boolean selectionChanged = false;
+ boolean selectionChanged = false;
/*
* The speed (in pixels) which the scrolling scrolls vertically/horizontally
@@ -204,7 +221,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private Timer scrollingVelocityTimer = null;
- private String[] bodyActionKeys;
+ String[] bodyActionKeys;
private boolean enableDebug = false;
@@ -280,19 +297,18 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private final HashSet<SelectionRange> selectedRowRanges = new HashSet<SelectionRange>();
- private boolean initializedAndAttached = false;
+ boolean initializedAndAttached = false;
/**
* Flag to indicate if a column width recalculation is needed due update.
*/
- private boolean headerChangedDuringUpdate = false;
+ boolean headerChangedDuringUpdate = false;
protected final TableHead tHead = new TableHead();
- private final TableFooter tFoot = new TableFooter();
+ final TableFooter tFoot = new TableFooter();
- private final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel(
- true);
+ final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel(true);
private KeyPressHandler navKeyPressHandler = new KeyPressHandler() {
public void onKeyPress(KeyPressEvent keyPressEvent) {
@@ -381,12 +397,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
};
- private int totalRows;
+ int totalRows;
private Set<String> collapsedColumns;
- private final RowRequestHandler rowRequestHandler;
- private VScrollTableBody scrollBody;
+ final RowRequestHandler rowRequestHandler;
+ VScrollTableBody scrollBody;
private int firstvisible = 0;
private boolean sortAscending;
private String sortColumn;
@@ -401,9 +417,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private String[] visibleColOrder;
private boolean initialContentReceived = false;
private Element scrollPositionElement;
- private boolean enabled;
- private boolean showColHeaders;
- private boolean showColFooters;
+ boolean enabled;
+ boolean showColHeaders;
+ boolean showColFooters;
/** flag to indicate that table body has changed */
private boolean isNewBody = true;
@@ -418,15 +434,15 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>();
private String height;
private String width = "";
- private boolean rendering = false;
+ boolean rendering = false;
private boolean hasFocus = false;
private int dragmode;
private int multiselectmode;
- private int tabIndex;
+ int tabIndex;
private TouchScrollDelegate touchScrollDelegate;
- private int lastRenderedHeight;
+ int lastRenderedHeight;
/**
* Values (serverCacheFirst+serverCacheLast) sent by server that tells which
@@ -440,8 +456,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* scrolling in the client will cause empty buttons to be rendered
* (cached=true request for non-existing components)
*/
- private int serverCacheFirst = -1;
- private int serverCacheLast = -1;
+ int serverCacheFirst = -1;
+ int serverCacheLast = -1;
public VScrollTable() {
setMultiSelectMode(MULTISELECT_MODE_DEFAULT);
@@ -808,211 +824,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return KeyCodes.KEY_END;
}
- /*
- * (non-Javadoc)
- *
- * @see
- * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
- * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
- */
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
-
- if (uidl.hasAttribute(ATTRIBUTE_PAGEBUFFER_FIRST)) {
- serverCacheFirst = uidl.getIntAttribute(ATTRIBUTE_PAGEBUFFER_FIRST);
- serverCacheLast = uidl.getIntAttribute(ATTRIBUTE_PAGEBUFFER_LAST);
- } else {
- serverCacheFirst = -1;
- serverCacheLast = -1;
- }
- /*
- * We need to do this before updateComponent since updateComponent calls
- * this.setHeight() which will calculate a new body height depending on
- * the space available.
- */
- if (uidl.hasAttribute("colfooters")) {
- showColFooters = uidl.getBooleanAttribute("colfooters");
- }
-
- tFoot.setVisible(showColFooters);
-
- if (client.updateComponent(this, uidl, true)) {
- rendering = false;
- return;
- }
-
- enabled = !uidl.hasAttribute("disabled");
-
- if (BrowserInfo.get().isIE8() && !enabled) {
- /*
- * The disabled shim will not cover the table body if it is relative
- * in IE8. See #7324
- */
- scrollBodyPanel.getElement().getStyle()
- .setPosition(Position.STATIC);
- } else if (BrowserInfo.get().isIE8()) {
- scrollBodyPanel.getElement().getStyle()
- .setPosition(Position.RELATIVE);
- }
-
- this.client = client;
- paintableId = uidl.getStringAttribute("id");
- immediate = uidl.getBooleanAttribute("immediate");
-
- int previousTotalRows = totalRows;
- updateTotalRows(uidl);
- boolean totalRowsChanged = (totalRows != previousTotalRows);
-
- updateDragMode(uidl);
-
- updateSelectionProperties(uidl);
-
- if (uidl.hasAttribute("alb")) {
- bodyActionKeys = uidl.getStringArrayAttribute("alb");
- } else {
- // Need to clear the actions if the action handlers have been
- // removed
- bodyActionKeys = null;
- }
-
- setCacheRateFromUIDL(uidl);
-
- recalcWidths = uidl.hasAttribute("recalcWidths");
- if (recalcWidths) {
- tHead.clear();
- tFoot.clear();
- }
-
- updatePageLength(uidl);
-
- updateFirstVisibleAndScrollIfNeeded(uidl);
-
- showRowHeaders = uidl.getBooleanAttribute("rowheaders");
- showColHeaders = uidl.getBooleanAttribute("colheaders");
-
- updateSortingProperties(uidl);
-
- boolean keyboardSelectionOverRowFetchInProgress = selectSelectedRows(uidl);
-
- updateActionMap(uidl);
-
- updateColumnProperties(uidl);
-
- UIDL ac = uidl.getChildByTagName("-ac");
- if (ac == null) {
- if (dropHandler != null) {
- // remove dropHandler if not present anymore
- dropHandler = null;
- }
- } else {
- if (dropHandler == null) {
- dropHandler = new VScrollTableDropHandler();
- }
- dropHandler.updateAcceptRules(ac);
- }
-
- UIDL partialRowAdditions = uidl.getChildByTagName("prows");
- UIDL partialRowUpdates = uidl.getChildByTagName("urows");
- if (partialRowUpdates != null || partialRowAdditions != null) {
- // we may have pending cache row fetch, cancel it. See #2136
- rowRequestHandler.cancel();
-
- updateRowsInBody(partialRowUpdates);
- addAndRemoveRows(partialRowAdditions);
- } else {
- UIDL rowData = uidl.getChildByTagName("rows");
- if (rowData != null) {
- // we may have pending cache row fetch, cancel it. See #2136
- rowRequestHandler.cancel();
-
- if (!recalcWidths && initializedAndAttached) {
- updateBody(rowData, uidl.getIntAttribute("firstrow"),
- uidl.getIntAttribute("rows"));
- if (headerChangedDuringUpdate) {
- triggerLazyColumnAdjustment(true);
- } else if (!isScrollPositionVisible()
- || totalRowsChanged
- || lastRenderedHeight != scrollBody
- .getOffsetHeight()) {
- // webkits may still bug with their disturbing scrollbar
- // bug, see #3457
- // Run overflow fix for the scrollable area
- // #6698 - If there's a scroll going on, don't abort it
- // by changing overflows as the length of the contents
- // *shouldn't* have changed (unless the number of rows
- // or the height of the widget has also changed)
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- Util.runWebkitOverflowAutoFix(scrollBodyPanel
- .getElement());
- }
- });
- }
- } else {
- initializeRows(uidl, rowData);
- }
- }
- }
-
- if (!isSelectable()) {
- scrollBody.addStyleName(CLASSNAME + "-body-noselection");
- } else {
- scrollBody.removeStyleName(CLASSNAME + "-body-noselection");
- }
-
- hideScrollPositionAnnotation();
- purgeUnregistryBag();
-
- // selection is no in sync with server, avoid excessive server visits by
- // clearing to flag used during the normal operation
- if (!keyboardSelectionOverRowFetchInProgress) {
- selectionChanged = false;
- }
-
- /*
- * This is called when the Home or page up button has been pressed in
- * selectable mode and the next selected row was not yet rendered in the
- * client
- */
- if (selectFirstItemInNextRender || focusFirstItemInNextRender) {
- selectFirstRenderedRowInViewPort(focusFirstItemInNextRender);
- selectFirstItemInNextRender = focusFirstItemInNextRender = false;
- }
-
- /*
- * This is called when the page down or end button has been pressed in
- * selectable mode and the next selected row was not yet rendered in the
- * client
- */
- if (selectLastItemInNextRender || focusLastItemInNextRender) {
- selectLastRenderedRowInViewPort(focusLastItemInNextRender);
- selectLastItemInNextRender = focusLastItemInNextRender = false;
- }
- multiselectPending = false;
-
- if (focusedRow != null) {
- if (!focusedRow.isAttached() && !rowRequestHandler.isRunning()) {
- // focused row has been orphaned, can't focus
- focusRowFromBody();
- }
- }
-
- tabIndex = uidl.hasAttribute("tabindex") ? uidl
- .getIntAttribute("tabindex") : 0;
- setProperTabIndex();
-
- resizeSortedColumnForSortIndicator();
-
- // Remember this to detect situations where overflow hack might be
- // needed during scrolling
- lastRenderedHeight = scrollBody.getOffsetHeight();
-
- rendering = false;
- headerChangedDuringUpdate = false;
-
- }
-
- private void initializeRows(UIDL uidl, UIDL rowData) {
+ void initializeRows(UIDL uidl, UIDL rowData) {
if (scrollBody != null) {
scrollBody.removeFromParent();
lazyUnregistryBag.add(scrollBody);
@@ -1035,7 +847,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
scrollBody.restoreRowVisibility();
}
- private void updateColumnProperties(UIDL uidl) {
+ void updateColumnProperties(UIDL uidl) {
updateColumnOrder(uidl);
updateCollapsedColumns(uidl);
@@ -1070,7 +882,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
- private boolean selectSelectedRows(UIDL uidl) {
+ boolean selectSelectedRows(UIDL uidl) {
boolean keyboardSelectionOverRowFetchInProgress = false;
if (uidl.hasVariable("selected")) {
@@ -1107,7 +919,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return keyboardSelectionOverRowFetchInProgress;
}
- private void updateSortingProperties(UIDL uidl) {
+ void updateSortingProperties(UIDL uidl) {
oldSortColumn = sortColumn;
if (uidl.hasVariable("sortascending")) {
sortAscending = uidl.getBooleanVariable("sortascending");
@@ -1115,7 +927,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
- private void resizeSortedColumnForSortIndicator() {
+ void resizeSortedColumnForSortIndicator() {
// Force recalculation of the captionContainer element inside the header
// cell to accomodate for the size of the sort arrow.
HeaderCell sortedHeader = tHead.getHeaderCell(sortColumn);
@@ -1130,7 +942,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
- private void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) {
+ void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) {
firstvisible = uidl.hasVariable("firstvisible") ? uidl
.getIntVariable("firstvisible") : 0;
if (firstvisible != lastRequestedFirstvisible && scrollBody != null) {
@@ -1145,7 +957,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return (int) (rowIx * scrollBody.getRowHeight());
}
- private void updatePageLength(UIDL uidl) {
+ void updatePageLength(UIDL uidl) {
int oldPageLength = pageLength;
if (uidl.hasAttribute("pagelength")) {
pageLength = uidl.getIntAttribute("pagelength");
@@ -1160,7 +972,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
- private void updateSelectionProperties(UIDL uidl) {
+ void updateSelectionProperties(UIDL uidl) {
setMultiSelectMode(uidl.hasAttribute("multiselectmode") ? uidl
.getIntAttribute("multiselectmode") : MULTISELECT_MODE_DEFAULT);
@@ -1169,18 +981,18 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
if (uidl.hasAttribute("selectmode")) {
if (uidl.getBooleanAttribute("readonly")) {
- selectMode = Table.SELECT_MODE_NONE;
+ selectMode = SelectMode.NONE;
} else if (uidl.getStringAttribute("selectmode").equals("multi")) {
- selectMode = Table.SELECT_MODE_MULTI;
+ selectMode = SelectMode.MULTI;
} else if (uidl.getStringAttribute("selectmode").equals("single")) {
- selectMode = Table.SELECT_MODE_SINGLE;
+ selectMode = SelectMode.SINGLE;
} else {
- selectMode = Table.SELECT_MODE_NONE;
+ selectMode = SelectMode.NONE;
}
}
}
- private void updateDragMode(UIDL uidl) {
+ void updateDragMode(UIDL uidl) {
dragmode = uidl.hasAttribute("dragmode") ? uidl
.getIntAttribute("dragmode") : 0;
if (BrowserInfo.get().isIE()) {
@@ -1217,7 +1029,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return totalRows;
}
- private void focusRowFromBody() {
+ void focusRowFromBody() {
if (selectedRowKeys.size() == 1) {
// try to focus a row currently selected and in viewport
String selectedRowKey = selectedRowKeys.iterator().next();
@@ -1245,7 +1057,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* @param focusOnly
* Should the focus only be moved to the last row
*/
- private void selectLastRenderedRowInViewPort(boolean focusOnly) {
+ void selectLastRenderedRowInViewPort(boolean focusOnly) {
int index = firstRowInViewPort + getFullyVisibleRowCount();
VScrollTableRow lastRowInViewport = scrollBody.getRowByRowIndex(index);
if (lastRowInViewport == null) {
@@ -1270,7 +1082,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* @param focusOnly
* Should the focus only be moved to the first row
*/
- private void selectFirstRenderedRowInViewPort(boolean focusOnly) {
+ void selectFirstRenderedRowInViewPort(boolean focusOnly) {
int index = firstRowInViewPort;
VScrollTableRow firstInViewport = scrollBody.getRowByRowIndex(index);
if (firstInViewport == null) {
@@ -1284,7 +1096,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
- private void setCacheRateFromUIDL(UIDL uidl) {
+ void setCacheRateFromUIDL(UIDL uidl) {
setCacheRate(uidl.hasAttribute("cr") ? uidl.getDoubleAttribute("cr")
: CACHE_RATE_DEFAULT);
}
@@ -1301,15 +1113,16 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* IScrollTableRows). This is done lazily as Table must survive from
* "subtreecaching" logic.
*/
- private void purgeUnregistryBag() {
+ void purgeUnregistryBag() {
for (Iterator<Panel> iterator = lazyUnregistryBag.iterator(); iterator
.hasNext();) {
- client.unregisterChildPaintables(iterator.next());
+ VPaintableMap.get(client)
+ .unregisterChildPaintables(iterator.next());
}
lazyUnregistryBag.clear();
}
- private void updateActionMap(UIDL mainUidl) {
+ void updateActionMap(UIDL mainUidl) {
UIDL actionsUidl = mainUidl.getChildByTagName("actions");
if (actionsUidl == null) {
return;
@@ -1411,7 +1224,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* @param reqRows
* amount of rows in data set
*/
- private void updateBody(UIDL uidl, int firstRow, int reqRows) {
+ void updateBody(UIDL uidl, int firstRow, int reqRows) {
if (uidl == null || reqRows < 1) {
// container is empty, remove possibly existing rows
if (firstRow <= 0) {
@@ -1428,7 +1241,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
discardRowsOutsideCacheWindow();
}
- private void updateRowsInBody(UIDL partialRowUpdates) {
+ void updateRowsInBody(UIDL partialRowUpdates) {
if (partialRowUpdates == null) {
return;
}
@@ -1561,20 +1374,20 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
private boolean isMultiSelectModeSimple() {
- return selectMode == Table.SELECT_MODE_MULTI
+ return selectMode == SelectMode.MULTI
&& multiselectmode == MULTISELECT_MODE_SIMPLE;
}
private boolean isSingleSelectMode() {
- return selectMode == Table.SELECT_MODE_SINGLE;
+ return selectMode == SelectMode.SINGLE;
}
private boolean isMultiSelectModeAny() {
- return selectMode == Table.SELECT_MODE_MULTI;
+ return selectMode == SelectMode.MULTI;
}
private boolean isMultiSelectModeDefault() {
- return selectMode == Table.SELECT_MODE_MULTI
+ return selectMode == SelectMode.MULTI
&& multiselectmode == MULTISELECT_MODE_DEFAULT;
}
@@ -1590,7 +1403,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
protected boolean isSelectable() {
- return selectMode > Table.SELECT_MODE_NONE;
+ return selectMode.getId() > SelectMode.NONE.getId();
}
private boolean isCollapsedColumn(String colKey) {
@@ -1766,7 +1579,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
client.updateVariable(paintableId, "columnorder", columnOrder, false);
- if (client.hasEventListeners(this, COLUMN_REORDER_EVENT_ID)) {
+ if (client.hasWidgetEventListeners(this, COLUMN_REORDER_EVENT_ID)) {
client.sendPendingVariableChanges();
}
}
@@ -2105,19 +1918,19 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
style.setDisplay(Display.BLOCK);
}
- private void hideScrollPositionAnnotation() {
+ void hideScrollPositionAnnotation() {
if (scrollPositionElement != null) {
DOM.setStyleAttribute(scrollPositionElement, "display", "none");
}
}
- private boolean isScrollPositionVisible() {
+ boolean isScrollPositionVisible() {
return scrollPositionElement != null
&& !scrollPositionElement.getStyle().getDisplay()
.equals(Display.NONE.toString());
}
- private class RowRequestHandler extends Timer {
+ class RowRequestHandler extends Timer {
private int reqFirstRow = 0;
private int reqRows = 0;
@@ -2292,11 +2105,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* of the caption container element by the correct amount
*/
public void resizeCaptionContainer(int rightSpacing) {
-
int captionContainerWidth = width
- colResizeWidget.getOffsetWidth() - rightSpacing;
- if (BrowserInfo.get().isIE6() || td.getClassName().contains("-asc")
+ if (td.getClassName().contains("-asc")
|| td.getClassName().contains("-desc")) {
// Leave room for the sort indicator
captionContainerWidth -= sortIndicator.getOffsetWidth();
@@ -2500,7 +2312,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* The click event
*/
private void fireHeaderClickedEvent(Event event) {
- if (client.hasEventListeners(VScrollTable.this,
+ if (client.hasWidgetEventListeners(VScrollTable.this,
HEADER_CLICK_EVENT_ID)) {
MouseEventDetails details = new MouseEventDetails(event);
client.updateVariable(paintableId, "headerClickEvent",
@@ -2756,8 +2568,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
int hw = captionContainer.getOffsetWidth()
+ scrollBody.getCellExtraWidth();
- if (BrowserInfo.get().isGecko()
- || BrowserInfo.get().isIE7()) {
+ if (BrowserInfo.get().isGecko()) {
hw += sortIndicator.getOffsetWidth();
}
if (columnIndex < 0) {
@@ -3024,12 +2835,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
public void setHorizontalScrollPosition(int scrollLeft) {
- if (BrowserInfo.get().isIE6()) {
- hTableWrapper.getStyle().setPosition(Position.RELATIVE);
- hTableWrapper.getStyle().setLeft(-scrollLeft, Unit.PX);
- } else {
- hTableWrapper.setScrollLeft(scrollLeft);
- }
+ hTableWrapper.setScrollLeft(scrollLeft);
}
public void setColumnCollapsingAllowed(boolean cc) {
@@ -3548,7 +3354,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* The click event
*/
private void fireFooterClickedEvent(Event event) {
- if (client.hasEventListeners(VScrollTable.this,
+ if (client.hasWidgetEventListeners(VScrollTable.this,
FOOTER_CLICK_EVENT_ID)) {
MouseEventDetails details = new MouseEventDetails(event);
client.updateVariable(paintableId, "footerClickEvent",
@@ -3880,12 +3686,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* The value of the leftScroll
*/
public void setHorizontalScrollPosition(int scrollLeft) {
- if (BrowserInfo.get().isIE6()) {
- hTableWrapper.getStyle().setProperty("position", "relative");
- hTableWrapper.getStyle().setPropertyPx("left", -scrollLeft);
- } else {
- hTableWrapper.setScrollLeft(scrollLeft);
- }
+ hTableWrapper.setScrollLeft(scrollLeft);
}
/**
@@ -4305,12 +4106,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
final VScrollTableRow toBeRemoved = (VScrollTableRow) renderedRows
.get(index);
// Unregister row tooltip
- client.registerTooltip(VScrollTable.this, toBeRemoved.getElement(),
- null);
+ client.registerWidgetTooltip(VScrollTable.this,
+ toBeRemoved.getElement(), null);
for (int i = 0; i < toBeRemoved.getElement().getChildCount(); i++) {
// Unregister cell tooltips
Element td = toBeRemoved.getElement().getChild(i).cast();
- client.registerTooltip(VScrollTable.this, td, null);
+ client.registerWidgetTooltip(VScrollTable.this, td, null);
}
lazyUnregistryBag.add(toBeRemoved);
tBodyElement.removeChild(toBeRemoved.getElement());
@@ -4569,10 +4370,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
String rowDescription = uidl.getStringAttribute("rowdescr");
if (rowDescription != null && !rowDescription.equals("")) {
TooltipInfo info = new TooltipInfo(rowDescription);
- client.registerTooltip(VScrollTable.this, rowElement, info);
+ client.registerWidgetTooltip(VScrollTable.this, rowElement,
+ info);
} else {
// Remove possibly previously set tooltip
- client.registerTooltip(VScrollTable.this, rowElement, null);
+ client.registerWidgetTooltip(VScrollTable.this, rowElement,
+ null);
}
tHead.getColumnAlignments();
@@ -4650,11 +4453,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
addCell(uidl, cell.toString(), aligns[col++], style,
isRenderHtmlInCells(), sorted, description);
} else {
- final Paintable cellContent = client
+ final VPaintableWidget cellContent = client
.getPaintable((UIDL) cell);
- addCell(uidl, (Widget) cellContent, aligns[col++],
- style, sorted);
+ addCell(uidl, cellContent.getWidgetForPaintable(),
+ aligns[col++], style, sorted);
paintComponent(cellContent, (UIDL) cell);
}
}
@@ -4728,7 +4531,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return index;
}
- protected void paintComponent(Paintable p, UIDL uidl) {
+ protected void paintComponent(VPaintableWidget p, UIDL uidl) {
if (isAttached()) {
p.updateFromUIDL(uidl, client);
} else {
@@ -4744,7 +4547,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
super.onAttach();
if (pendingComponentPaints != null) {
for (UIDL uidl : pendingComponentPaints) {
- Paintable paintable = client.getPaintable(uidl);
+ VPaintableWidget paintable = (VPaintableWidget) VPaintableMap
+ .get(client).getPaintable(uidl.getId());
paintable.updateFromUIDL(uidl, client);
}
pendingComponentPaints.clear();
@@ -4807,10 +4611,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
if (description != null && !description.equals("")) {
TooltipInfo info = new TooltipInfo(description);
- client.registerTooltip(VScrollTable.this, td, info);
+ client.registerWidgetTooltip(VScrollTable.this, td, info);
} else {
// Remove possibly previously set tooltip
- client.registerTooltip(VScrollTable.this, td, null);
+ client.registerWidgetTooltip(VScrollTable.this, td, null);
}
td.appendChild(container);
@@ -4889,7 +4693,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*/
private boolean handleClickEvent(Event event, Element targetTdOrTr,
boolean immediate) {
- if (!client.hasEventListeners(VScrollTable.this,
+ if (!client.hasWidgetEventListeners(VScrollTable.this,
ITEM_CLICK_EVENT_ID)) {
// Don't send an event if nobody is listening
return false;
@@ -4933,22 +4737,24 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
if (!containsWidget) {
// Only text nodes has tooltips
- if (client.getTooltipTitleInfo(VScrollTable.this,
- target) != null) {
+ if (VPaintableMap.get(client).getWidgetTooltipInfo(
+ VScrollTable.this, target) != null) {
// Cell has description, use it
- client.handleTooltipEvent(event, VScrollTable.this,
- target);
+ client.handleWidgetTooltipEvent(event,
+ VScrollTable.this, target);
} else {
// Cell might have row description, use row
// description
- client.handleTooltipEvent(event, VScrollTable.this,
+ client.handleWidgetTooltipEvent(event,
+ VScrollTable.this,
target.getParentElement());
}
}
} else {
// Table row (tr)
- client.handleTooltipEvent(event, VScrollTable.this, target);
+ client.handleWidgetTooltipEvent(event, VScrollTable.this,
+ target);
}
}
@@ -4964,7 +4770,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
showContextMenu(event);
if (enabled
&& (actionKeys != null || client
- .hasEventListeners(VScrollTable.this,
+ .hasWidgetEventListeners(
+ VScrollTable.this,
ITEM_CLICK_EVENT_ID))) {
/*
* Prevent browser context menu only if there are
@@ -5253,7 +5060,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
Element targetTdOrTr) {
mDown = true;
VTransferable transferable = new VTransferable();
- transferable.setDragSource(VScrollTable.this);
+ transferable.setDragSource(VPaintableMap.get(client)
+ .getPaintable(VScrollTable.this));
transferable.setData("itemId", "" + rowKey);
NodeList<TableCellElement> cells = rowElement.getCells();
for (int i = 0; i < cells.getLength(); i++) {
@@ -5523,13 +5331,13 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
- public boolean requestLayout(Set<Paintable> children) {
+ public boolean requestLayout(Set<Widget> children) {
// row size should never change and system wouldn't event
// survive as this is a kind of fake paitable
return true;
}
- public void updateCaption(Paintable component, UIDL uidl) {
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
// NOP, not rendered
}
@@ -5538,6 +5346,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
// Component container interface faked here to get layouts
// render properly
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
}
protected class VScrollTableGeneratedRow extends VScrollTableRow {
@@ -5671,7 +5483,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
if (!hasFocus) {
scrollBodyPanel.setFocus(true);
}
+
}
+
}
/**
@@ -5976,28 +5790,24 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
private int contentAreaBorderHeight = -1;
private int scrollLeft;
private int scrollTop;
- private VScrollTableDropHandler dropHandler;
+ VScrollTableDropHandler dropHandler;
private boolean navKeyDown;
- private boolean multiselectPending;
+ boolean multiselectPending;
/**
* @return border top + border bottom of the scrollable area of table
*/
private int getContentAreaBorderHeight() {
if (contentAreaBorderHeight < 0) {
- if (BrowserInfo.get().isIE7() || BrowserInfo.get().isIE6()) {
- contentAreaBorderHeight = Util
- .measureVerticalBorder(scrollBodyPanel.getElement());
- } else {
- DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow",
- "hidden");
- int oh = scrollBodyPanel.getOffsetHeight();
- int ch = scrollBodyPanel.getElement().getPropertyInt(
- "clientHeight");
- contentAreaBorderHeight = oh - ch;
- DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow",
- "auto");
- }
+
+ DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow",
+ "hidden");
+ int oh = scrollBodyPanel.getOffsetHeight();
+ int ch = scrollBodyPanel.getElement()
+ .getPropertyInt("clientHeight");
+ contentAreaBorderHeight = oh - ch;
+ DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow",
+ "auto");
}
return contentAreaBorderHeight;
}
@@ -6330,8 +6140,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
@Override
- public Paintable getPaintable() {
- return VScrollTable.this;
+ public VPaintableWidget getPaintable() {
+ return VPaintableMap.get(client).getPaintable(VScrollTable.this);
}
public ApplicationConnection getApplicationConnection() {
@@ -6768,7 +6578,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* actions may need focus.
*
*/
- private void setProperTabIndex() {
+ void setProperTabIndex() {
int storedScrollTop = 0;
int storedScrollLeft = 0;
@@ -6891,4 +6701,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
VConsole.error(msg);
}
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java
new file mode 100644
index 0000000000..0c41ed1aa3
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java
@@ -0,0 +1,254 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VScrollTablePaintable extends VAbstractPaintableWidget {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
+ * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
+ */
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+
+ if (uidl.hasAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST)) {
+ getWidgetForPaintable().serverCacheFirst = uidl
+ .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST);
+ getWidgetForPaintable().serverCacheLast = uidl
+ .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_LAST);
+ } else {
+ getWidgetForPaintable().serverCacheFirst = -1;
+ getWidgetForPaintable().serverCacheLast = -1;
+ }
+ /*
+ * We need to do this before updateComponent since updateComponent calls
+ * this.setHeight() which will calculate a new body height depending on
+ * the space available.
+ */
+ if (uidl.hasAttribute("colfooters")) {
+ getWidgetForPaintable().showColFooters = uidl
+ .getBooleanAttribute("colfooters");
+ }
+
+ getWidgetForPaintable().tFoot
+ .setVisible(getWidgetForPaintable().showColFooters);
+
+ if (client.updateComponent(this, uidl, true)) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ getWidgetForPaintable().enabled = !uidl.hasAttribute("disabled");
+
+ if (BrowserInfo.get().isIE8() && !getWidgetForPaintable().enabled) {
+ /*
+ * The disabled shim will not cover the table body if it is relative
+ * in IE8. See #7324
+ */
+ getWidgetForPaintable().scrollBodyPanel.getElement().getStyle()
+ .setPosition(Position.STATIC);
+ } else if (BrowserInfo.get().isIE8()) {
+ getWidgetForPaintable().scrollBodyPanel.getElement().getStyle()
+ .setPosition(Position.RELATIVE);
+ }
+
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getStringAttribute("id");
+ getWidgetForPaintable().immediate = uidl
+ .getBooleanAttribute("immediate");
+
+ int previousTotalRows = getWidgetForPaintable().totalRows;
+ getWidgetForPaintable().updateTotalRows(uidl);
+ boolean totalRowsChanged = (getWidgetForPaintable().totalRows != previousTotalRows);
+
+ getWidgetForPaintable().updateDragMode(uidl);
+
+ getWidgetForPaintable().updateSelectionProperties(uidl);
+
+ if (uidl.hasAttribute("alb")) {
+ getWidgetForPaintable().bodyActionKeys = uidl
+ .getStringArrayAttribute("alb");
+ } else {
+ // Need to clear the actions if the action handlers have been
+ // removed
+ getWidgetForPaintable().bodyActionKeys = null;
+ }
+
+ getWidgetForPaintable().setCacheRateFromUIDL(uidl);
+
+ getWidgetForPaintable().recalcWidths = uidl
+ .hasAttribute("recalcWidths");
+ if (getWidgetForPaintable().recalcWidths) {
+ getWidgetForPaintable().tHead.clear();
+ getWidgetForPaintable().tFoot.clear();
+ }
+
+ getWidgetForPaintable().updatePageLength(uidl);
+
+ getWidgetForPaintable().updateFirstVisibleAndScrollIfNeeded(uidl);
+
+ getWidgetForPaintable().showRowHeaders = uidl
+ .getBooleanAttribute("rowheaders");
+ getWidgetForPaintable().showColHeaders = uidl
+ .getBooleanAttribute("colheaders");
+
+ getWidgetForPaintable().updateSortingProperties(uidl);
+
+ boolean keyboardSelectionOverRowFetchInProgress = getWidgetForPaintable()
+ .selectSelectedRows(uidl);
+
+ getWidgetForPaintable().updateActionMap(uidl);
+
+ getWidgetForPaintable().updateColumnProperties(uidl);
+
+ UIDL ac = uidl.getChildByTagName("-ac");
+ if (ac == null) {
+ if (getWidgetForPaintable().dropHandler != null) {
+ // remove dropHandler if not present anymore
+ getWidgetForPaintable().dropHandler = null;
+ }
+ } else {
+ if (getWidgetForPaintable().dropHandler == null) {
+ getWidgetForPaintable().dropHandler = getWidgetForPaintable().new VScrollTableDropHandler();
+ }
+ getWidgetForPaintable().dropHandler.updateAcceptRules(ac);
+ }
+
+ UIDL partialRowAdditions = uidl.getChildByTagName("prows");
+ UIDL partialRowUpdates = uidl.getChildByTagName("urows");
+ if (partialRowUpdates != null || partialRowAdditions != null) {
+ // we may have pending cache row fetch, cancel it. See #2136
+ getWidgetForPaintable().rowRequestHandler.cancel();
+
+ getWidgetForPaintable().updateRowsInBody(partialRowUpdates);
+ getWidgetForPaintable().addAndRemoveRows(partialRowAdditions);
+ } else {
+ UIDL rowData = uidl.getChildByTagName("rows");
+ if (rowData != null) {
+ // we may have pending cache row fetch, cancel it. See #2136
+ getWidgetForPaintable().rowRequestHandler.cancel();
+
+ if (!getWidgetForPaintable().recalcWidths
+ && getWidgetForPaintable().initializedAndAttached) {
+ getWidgetForPaintable().updateBody(rowData,
+ uidl.getIntAttribute("firstrow"),
+ uidl.getIntAttribute("rows"));
+ if (getWidgetForPaintable().headerChangedDuringUpdate) {
+ getWidgetForPaintable().triggerLazyColumnAdjustment(
+ true);
+ } else if (!getWidgetForPaintable()
+ .isScrollPositionVisible()
+ || totalRowsChanged
+ || getWidgetForPaintable().lastRenderedHeight != getWidgetForPaintable().scrollBody
+ .getOffsetHeight()) {
+ // webkits may still bug with their disturbing scrollbar
+ // bug, see #3457
+ // Run overflow fix for the scrollable area
+ // #6698 - If there's a scroll going on, don't abort it
+ // by changing overflows as the length of the contents
+ // *shouldn't* have changed (unless the number of rows
+ // or the height of the widget has also changed)
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ Util.runWebkitOverflowAutoFix(getWidgetForPaintable().scrollBodyPanel
+ .getElement());
+ }
+ });
+ }
+ } else {
+ getWidgetForPaintable().initializeRows(uidl, rowData);
+ }
+ }
+ }
+
+ if (!getWidgetForPaintable().isSelectable()) {
+ getWidgetForPaintable().scrollBody
+ .addStyleName(VScrollTable.CLASSNAME + "-body-noselection");
+ } else {
+ getWidgetForPaintable().scrollBody
+ .removeStyleName(VScrollTable.CLASSNAME
+ + "-body-noselection");
+ }
+
+ getWidgetForPaintable().hideScrollPositionAnnotation();
+ getWidgetForPaintable().purgeUnregistryBag();
+
+ // selection is no in sync with server, avoid excessive server visits by
+ // clearing to flag used during the normal operation
+ if (!keyboardSelectionOverRowFetchInProgress) {
+ getWidgetForPaintable().selectionChanged = false;
+ }
+
+ /*
+ * This is called when the Home or page up button has been pressed in
+ * selectable mode and the next selected row was not yet rendered in the
+ * client
+ */
+ if (getWidgetForPaintable().selectFirstItemInNextRender
+ || getWidgetForPaintable().focusFirstItemInNextRender) {
+ getWidgetForPaintable().selectFirstRenderedRowInViewPort(
+ getWidgetForPaintable().focusFirstItemInNextRender);
+ getWidgetForPaintable().selectFirstItemInNextRender = getWidgetForPaintable().focusFirstItemInNextRender = false;
+ }
+
+ /*
+ * This is called when the page down or end button has been pressed in
+ * selectable mode and the next selected row was not yet rendered in the
+ * client
+ */
+ if (getWidgetForPaintable().selectLastItemInNextRender
+ || getWidgetForPaintable().focusLastItemInNextRender) {
+ getWidgetForPaintable().selectLastRenderedRowInViewPort(
+ getWidgetForPaintable().focusLastItemInNextRender);
+ getWidgetForPaintable().selectLastItemInNextRender = getWidgetForPaintable().focusLastItemInNextRender = false;
+ }
+ getWidgetForPaintable().multiselectPending = false;
+
+ if (getWidgetForPaintable().focusedRow != null) {
+ if (!getWidgetForPaintable().focusedRow.isAttached()
+ && !getWidgetForPaintable().rowRequestHandler.isRunning()) {
+ // focused row has been orphaned, can't focus
+ getWidgetForPaintable().focusRowFromBody();
+ }
+ }
+
+ getWidgetForPaintable().tabIndex = uidl.hasAttribute("tabindex") ? uidl
+ .getIntAttribute("tabindex") : 0;
+ getWidgetForPaintable().setProperTabIndex();
+
+ getWidgetForPaintable().resizeSortedColumnForSortIndicator();
+
+ // Remember this to detect situations where overflow hack might be
+ // needed during scrolling
+ getWidgetForPaintable().lastRenderedHeight = getWidgetForPaintable().scrollBody
+ .getOffsetHeight();
+
+ getWidgetForPaintable().rendering = false;
+ getWidgetForPaintable().headerChangedDuringUpdate = false;
+
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VScrollTable.class);
+ }
+
+ @Override
+ public VScrollTable getWidgetForPaintable() {
+ return (VScrollTable) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java
index 4a46346613..6e2ff0930e 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java
@@ -13,15 +13,14 @@ import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
-public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
+public class VSlider extends SimpleFocusablePanel implements Field,
ContainerResizedListener {
public static final String CLASSNAME = "v-slider";
@@ -36,19 +35,16 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
String id;
- private boolean immediate;
- private boolean disabled;
- private boolean readonly;
- private boolean scrollbarStyle;
+ boolean immediate;
+ boolean disabled;
+ boolean readonly;
private int acceleration = 1;
- private int handleSize;
- private double min;
- private double max;
- private int resolution;
- private Double value;
- private boolean vertical;
- private boolean arrows;
+ double min;
+ double max;
+ int resolution;
+ Double value;
+ boolean vertical;
private final HTML feedback = new HTML("", false);
private final VOverlay feedbackPopup = new VOverlay(true, false, true) {
@@ -115,67 +111,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
feedbackPopup.setWidget(feedback);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
- this.client = client;
- id = uidl.getId();
-
- // Ensure correct implementation
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- immediate = uidl.getBooleanAttribute("immediate");
- disabled = uidl.getBooleanAttribute("disabled");
- readonly = uidl.getBooleanAttribute("readonly");
-
- vertical = uidl.hasAttribute("vertical");
- arrows = uidl.hasAttribute("arrows");
-
- String style = "";
- if (uidl.hasAttribute("style")) {
- style = uidl.getStringAttribute("style");
- }
-
- scrollbarStyle = style.indexOf("scrollbar") > -1;
-
- if (arrows) {
- DOM.setStyleAttribute(smaller, "display", "block");
- DOM.setStyleAttribute(bigger, "display", "block");
- }
-
- if (vertical) {
- addStyleName(CLASSNAME + "-vertical");
- } else {
- removeStyleName(CLASSNAME + "-vertical");
- }
-
- min = uidl.getDoubleAttribute("min");
- max = uidl.getDoubleAttribute("max");
- resolution = uidl.getIntAttribute("resolution");
- value = new Double(uidl.getDoubleVariable("value"));
-
- setFeedbackValue(value);
-
- handleSize = uidl.getIntAttribute("hsize");
-
- buildBase();
-
- if (!vertical) {
- // Draw handle with a delay to allow base to gain maximum width
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- buildHandle();
- setValue(value, false);
- }
- });
- } else {
- buildHandle();
- setValue(value, false);
- }
- }
-
- private void setFeedbackValue(double value) {
+ void setFeedbackValue(double value) {
String currentValue = "" + value;
if (resolution == 0) {
currentValue = "" + new Double(value).intValue();
@@ -198,7 +134,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
}
}
- private void buildBase() {
+ void buildBase() {
final String styleAttribute = vertical ? "height" : "width";
final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
@@ -232,37 +168,17 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
// TODO attach listeners for focusing and arrow keys
}
- private void buildHandle() {
- final String styleAttribute = vertical ? "height" : "width";
+ void buildHandle() {
final String handleAttribute = vertical ? "marginTop" : "marginLeft";
- final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
DOM.setStyleAttribute(handle, handleAttribute, "0");
- if (scrollbarStyle) {
- // Only stretch the handle if scrollbar style is set.
- int s = (int) (Double.parseDouble(DOM.getElementProperty(base,
- domProperty)) / 100 * handleSize);
- if (handleSize == -1) {
- final int baseS = Integer.parseInt(DOM.getElementProperty(base,
- domProperty));
- final double range = (max - min) * (resolution + 1) * 3;
- s = (int) (baseS - range);
- }
- if (s < 3) {
- s = 3;
- }
- DOM.setStyleAttribute(handle, styleAttribute, s + "px");
- } else {
- DOM.setStyleAttribute(handle, styleAttribute, "");
- }
-
// Restore visibility
DOM.setStyleAttribute(handle, "visibility", "visible");
}
- private void setValue(Double value, boolean updateToServer) {
+ void setValue(Double value, boolean updateToServer) {
if (value == null) {
return;
}
@@ -300,9 +216,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
p = 0;
}
if (vertical) {
- // IE6 rounding behaves a little unstable, reduce one pixel so the
- // containing element (base) won't expand without limits
- p = range - p - (BrowserInfo.get().isIE6() ? 1 : 0);
+ p = range - p;
}
final double pos = p;
@@ -356,7 +270,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
} else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
feedbackPopup.show();
}
- if(Util.isTouchEvent(event)) {
+ if (Util.isTouchEvent(event)) {
event.preventDefault(); // avoid simulated events
event.stopPropagation();
}
@@ -596,4 +510,8 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field,
protected int getNavigationRightKey() {
return KeyCodes.KEY_RIGHT;
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSliderPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VSliderPaintable.java
new file mode 100644
index 0000000000..c4e484a76b
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VSliderPaintable.java
@@ -0,0 +1,78 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VSliderPaintable extends VAbstractPaintableWidget {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().id = uidl.getId();
+
+ // Ensure correct implementation
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ getWidgetForPaintable().immediate = uidl
+ .getBooleanAttribute("immediate");
+ getWidgetForPaintable().disabled = uidl.getBooleanAttribute("disabled");
+ getWidgetForPaintable().readonly = uidl.getBooleanAttribute("readonly");
+
+ getWidgetForPaintable().vertical = uidl.hasAttribute("vertical");
+
+ String style = "";
+ if (uidl.hasAttribute("style")) {
+ style = uidl.getStringAttribute("style");
+ }
+
+ if (getWidgetForPaintable().vertical) {
+ getWidgetForPaintable().addStyleName(
+ VSlider.CLASSNAME + "-vertical");
+ } else {
+ getWidgetForPaintable().removeStyleName(
+ VSlider.CLASSNAME + "-vertical");
+ }
+
+ getWidgetForPaintable().min = uidl.getDoubleAttribute("min");
+ getWidgetForPaintable().max = uidl.getDoubleAttribute("max");
+ getWidgetForPaintable().resolution = uidl.getIntAttribute("resolution");
+ getWidgetForPaintable().value = new Double(
+ uidl.getDoubleVariable("value"));
+
+ getWidgetForPaintable().setFeedbackValue(getWidgetForPaintable().value);
+
+ getWidgetForPaintable().buildBase();
+
+ if (!getWidgetForPaintable().vertical) {
+ // Draw handle with a delay to allow base to gain maximum width
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ getWidgetForPaintable().buildHandle();
+ getWidgetForPaintable().setValue(
+ getWidgetForPaintable().value, false);
+ }
+ });
+ } else {
+ getWidgetForPaintable().buildHandle();
+ getWidgetForPaintable().setValue(getWidgetForPaintable().value,
+ false);
+ }
+ }
+
+ @Override
+ public VSlider getWidgetForPaintable() {
+ return (VSlider) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VSlider.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java
index ff1e2e6b78..3902f064a5 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java
@@ -4,9 +4,9 @@
package com.vaadin.terminal.gwt.client.ui;
-public class VSplitPanelHorizontal extends VSplitPanel {
+public class VSplitPanelHorizontal extends VAbstractSplitPanel {
public VSplitPanelHorizontal() {
- super(VSplitPanel.ORIENTATION_HORIZONTAL);
+ super(VAbstractSplitPanel.ORIENTATION_HORIZONTAL);
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java
index dcf7622e50..e61f8cf5e5 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java
@@ -4,9 +4,9 @@
package com.vaadin.terminal.gwt.client.ui;
-public class VSplitPanelVertical extends VSplitPanel {
+public class VSplitPanelVertical extends VAbstractSplitPanel {
public VSplitPanelVertical() {
- super(VSplitPanel.ORIENTATION_VERTICAL);
+ super(VAbstractSplitPanel.ORIENTATION_VERTICAL);
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java b/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java
deleted file mode 100644
index d3cb3130b0..0000000000
--- a/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Set;
-
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.Grid;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-/**
- * TODO make this work (just an early prototype). We may want to have paging
- * style table which will be much lighter than VScrollTable is.
- */
-public class VTablePaging extends Composite implements Table, Paintable,
- ClickHandler {
-
- private final Grid tBody = new Grid();
- private final Button nextPage = new Button("&gt;");
- private final Button prevPage = new Button("&lt;");
- private final Button firstPage = new Button("&lt;&lt;");
- private final Button lastPage = new Button("&gt;&gt;");
-
- private int pageLength = 15;
-
- private boolean rowHeaders = false;
-
- private ApplicationConnection client;
- private String id;
-
- private boolean immediate = false;
-
- private int selectMode = Table.SELECT_MODE_NONE;
-
- private final ArrayList<String> selectedRowKeys = new ArrayList<String>();
-
- private int totalRows;
-
- private final HashMap<?, ?> visibleColumns = new HashMap<Object, Object>();
-
- private int rows;
-
- private int firstRow;
- private boolean sortAscending = true;
- private final HorizontalPanel pager;
-
- public HashMap<String, TableRow> rowKeysToTableRows = new HashMap<String, TableRow>();
-
- public VTablePaging() {
-
- tBody.setStyleName("itable-tbody");
-
- final VerticalPanel panel = new VerticalPanel();
-
- pager = new HorizontalPanel();
- pager.add(firstPage);
- firstPage.addClickHandler(this);
- pager.add(prevPage);
- prevPage.addClickHandler(this);
- pager.add(nextPage);
- nextPage.addClickHandler(this);
- pager.add(lastPage);
- lastPage.addClickHandler(this);
-
- panel.add(pager);
- panel.add(tBody);
-
- initWidget(panel);
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- this.client = client;
- id = uidl.getStringAttribute("id");
- immediate = uidl.getBooleanAttribute("immediate");
- totalRows = uidl.getIntAttribute("totalrows");
- pageLength = uidl.getIntAttribute("pagelength");
- firstRow = uidl.getIntAttribute("firstrow");
- rows = uidl.getIntAttribute("rows");
-
- if (uidl.hasAttribute("selectmode")) {
- if (uidl.getStringAttribute("selectmode").equals("multi")) {
- selectMode = Table.SELECT_MODE_MULTI;
- } else {
- selectMode = Table.SELECT_MODE_SINGLE;
- }
-
- if (uidl.hasAttribute("selected")) {
- final Set<String> selectedKeys = uidl
- .getStringArrayVariableAsSet("selected");
- selectedRowKeys.clear();
- for (final Iterator<String> it = selectedKeys.iterator(); it
- .hasNext();) {
- selectedRowKeys.add(it.next());
- }
- }
- }
-
- if (uidl.hasVariable("sortascending")) {
- sortAscending = uidl.getBooleanVariable("sortascending");
- }
-
- if (uidl.hasAttribute("rowheaders")) {
- rowHeaders = true;
- }
-
- UIDL rowData = null;
- UIDL visibleColumns = null;
- for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext();) {
- final UIDL c = (UIDL) it.next();
- if (c.getTag().equals("rows")) {
- rowData = c;
- } else if (c.getTag().equals("actions")) {
- updateActionMap(c);
- } else if (c.getTag().equals("visiblecolumns")) {
- visibleColumns = c;
- }
- }
- tBody.resize(rows + 1, uidl.getIntAttribute("cols")
- + (rowHeaders ? 1 : 0));
- updateHeader(visibleColumns);
- updateBody(rowData);
-
- updatePager();
- }
-
- private void updateHeader(UIDL c) {
- final Iterator<?> it = c.getChildIterator();
- visibleColumns.clear();
- int colIndex = (rowHeaders ? 1 : 0);
- while (it.hasNext()) {
- final UIDL col = (UIDL) it.next();
- final String cid = col.getStringAttribute("cid");
- if (!col.hasAttribute("collapsed")) {
- tBody.setWidget(0, colIndex,
- new HeaderCell(cid, col.getStringAttribute("caption")));
-
- }
- colIndex++;
- }
- }
-
- private void updateActionMap(UIDL c) {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * Updates row data from uidl. UpdateFromUIDL delegates updating tBody to
- * this method.
- *
- * Updates may be to different part of tBody, depending on update type. It
- * can be initial row data, scroll up, scroll down...
- *
- * @param uidl
- * which contains row data
- */
- private void updateBody(UIDL uidl) {
- final Iterator<?> it = uidl.getChildIterator();
-
- int curRowIndex = 1;
- while (it.hasNext()) {
- final UIDL rowUidl = (UIDL) it.next();
- final TableRow row = new TableRow(curRowIndex,
- String.valueOf(rowUidl.getIntAttribute("key")),
- rowUidl.hasAttribute("selected"));
- int colIndex = 0;
- if (rowHeaders) {
- tBody.setWidget(curRowIndex, colIndex, new BodyCell(row,
- rowUidl.getStringAttribute("caption")));
- colIndex++;
- }
- final Iterator<?> cells = rowUidl.getChildIterator();
- while (cells.hasNext()) {
- final Object cell = cells.next();
- if (cell instanceof String) {
- tBody.setWidget(curRowIndex, colIndex, new BodyCell(row,
- (String) cell));
- } else {
- final Paintable cellContent = client
- .getPaintable((UIDL) cell);
- final BodyCell bodyCell = new BodyCell(row);
- bodyCell.setWidget((Widget) cellContent);
- tBody.setWidget(curRowIndex, colIndex, bodyCell);
- }
- colIndex++;
- }
- curRowIndex++;
- }
- }
-
- private void updatePager() {
- if (pageLength == 0) {
- pager.setVisible(false);
- return;
- }
- if (isFirstPage()) {
- firstPage.setEnabled(false);
- prevPage.setEnabled(false);
- } else {
- firstPage.setEnabled(true);
- prevPage.setEnabled(true);
- }
- if (hasNextPage()) {
- nextPage.setEnabled(true);
- lastPage.setEnabled(true);
- } else {
- nextPage.setEnabled(false);
- lastPage.setEnabled(false);
-
- }
- }
-
- private boolean hasNextPage() {
- if (firstRow + rows + 1 > totalRows) {
- return false;
- }
- return true;
- }
-
- private boolean isFirstPage() {
- if (firstRow == 0) {
- return true;
- }
- return false;
- }
-
- public void onClick(ClickEvent event) {
- Object sender = event.getSource();
- if (sender instanceof Button) {
- if (sender == firstPage) {
- client.updateVariable(id, "firstvisible", 0, true);
- } else if (sender == nextPage) {
- client.updateVariable(id, "firstvisible",
- firstRow + pageLength, true);
- } else if (sender == prevPage) {
- int newFirst = firstRow - pageLength;
- if (newFirst < 0) {
- newFirst = 0;
- }
- client.updateVariable(id, "firstvisible", newFirst, true);
- } else if (sender == lastPage) {
- client.updateVariable(id, "firstvisible", totalRows
- - pageLength, true);
- }
- }
- if (sender instanceof HeaderCell) {
- final HeaderCell hCell = (HeaderCell) sender;
- client.updateVariable(id, "sortcolumn", hCell.getCid(), false);
- client.updateVariable(id, "sortascending", (sortAscending ? false
- : true), true);
- }
- }
-
- private class HeaderCell extends HTML {
-
- private String cid;
-
- public String getCid() {
- return cid;
- }
-
- public void setCid(String pid) {
- cid = pid;
- }
-
- HeaderCell(String pid, String caption) {
- super();
- cid = pid;
- addClickHandler(VTablePaging.this);
- setText(caption);
- // TODO remove debug color
- DOM.setStyleAttribute(getElement(), "color", "brown");
- DOM.setStyleAttribute(getElement(), "font-weight", "bold");
- }
- }
-
- /**
- * Abstraction of table cell content. In needs to know on which row it is in
- * case of context click.
- *
- * @author mattitahvonen
- */
- public class BodyCell extends SimplePanel {
- private final TableRow row;
-
- public BodyCell(TableRow row) {
- super();
- sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT);
- this.row = row;
- }
-
- public BodyCell(TableRow row2, String textContent) {
- super();
- sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT);
- row = row2;
- setWidget(new Label(textContent));
- }
-
- @Override
- public void onBrowserEvent(Event event) {
- System.out.println("CEll event: " + event.toString());
- switch (DOM.eventGetType(event)) {
- case Event.BUTTON_RIGHT:
- row.showContextMenu(event);
- Window.alert("context menu un-implemented");
- DOM.eventCancelBubble(event, true);
- break;
- case Event.BUTTON_LEFT:
- if (selectMode > Table.SELECT_MODE_NONE) {
- row.toggleSelected();
- }
- break;
- default:
- break;
- }
- super.onBrowserEvent(event);
- }
- }
-
- private class TableRow {
-
- private final String key;
- private final int rowIndex;
- private boolean selected = false;
-
- public TableRow(int rowIndex, String rowKey, boolean selected) {
- rowKeysToTableRows.put(rowKey, this);
- this.rowIndex = rowIndex;
- key = rowKey;
- setSelected(selected);
- }
-
- /**
- * This method is used to set row status. Does not change value on
- * server.
- *
- * @param selected
- */
- public void setSelected(boolean sel) {
- selected = sel;
- if (selected) {
- selectedRowKeys.add(key);
- DOM.setStyleAttribute(
- tBody.getRowFormatter().getElement(rowIndex),
- "background", "yellow");
-
- } else {
- selectedRowKeys.remove(key);
- DOM.setStyleAttribute(
- tBody.getRowFormatter().getElement(rowIndex),
- "background", "transparent");
- }
- }
-
- public void setContextMenuOptions(HashMap<?, ?> options) {
-
- }
-
- /**
- * Toggles rows select state. Also updates state to server according to
- * tables immediate flag.
- *
- */
- public void toggleSelected() {
- if (selected) {
- setSelected(false);
- } else {
- if (selectMode == Table.SELECT_MODE_SINGLE) {
- deselectAll();
- }
- setSelected(true);
- }
- client.updateVariable(
- id,
- "selected",
- selectedRowKeys.toArray(new String[selectedRowKeys.size()]),
- immediate);
- }
-
- /**
- * Shows context menu for this row.
- *
- * @param event
- * Event which triggered context menu. Correct place for
- * context menu can be determined with it.
- */
- public void showContextMenu(Event event) {
- System.out.println("TODO: Show context menu");
- }
- }
-
- public void deselectAll() {
- final Object[] keys = selectedRowKeys.toArray();
- for (int i = 0; i < keys.length; i++) {
- final TableRow tableRow = rowKeysToTableRows.get(keys[i]);
- if (tableRow != null) {
- tableRow.setSelected(false);
- }
- }
- // still ensure all selects are removed from
- selectedRowKeys.clear();
- }
-
- public void add(Widget w) {
- // TODO Auto-generated method stub
-
- }
-
- public void clear() {
- // TODO Auto-generated method stub
-
- }
-
- public Iterator<Widget> iterator() {
- // TODO Auto-generated method stub
- return null;
- }
-
- public boolean remove(Widget w) {
- // TODO Auto-generated method stub
- return false;
- }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
index d30d999d16..553a4d673e 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
@@ -23,13 +23,15 @@ import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.TooltipInfo;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.label.VLabel;
public class VTabsheet extends VTabsheetBase {
@@ -52,7 +54,7 @@ public class VTabsheet extends VTabsheetBase {
/**
* Representation of a single "tab" shown in the TabBar
- *
+ *
*/
private static class Tab extends SimplePanel {
private static final String TD_CLASSNAME = CLASSNAME + "-tabitemcell";
@@ -204,9 +206,10 @@ public class VTabsheet extends VTabsheetBase {
if (uidl.hasAttribute(ATTRIBUTE_ERROR)) {
tooltipInfo.setErrorUidl(uidl.getErrors());
}
- client.registerTooltip(getTabsheet(), getElement(), tooltipInfo);
+ client.registerWidgetTooltip(getTabsheet(), getElement(),
+ tooltipInfo);
} else {
- client.registerTooltip(getTabsheet(), getElement(), null);
+ client.registerWidgetTooltip(getTabsheet(), getElement(), null);
}
boolean ret = super.updateCaption(uidl);
@@ -234,40 +237,13 @@ public class VTabsheet extends VTabsheetBase {
if (event.getTypeInt() == Event.ONLOAD) {
getTabsheet().tabSizeMightHaveChanged(getTab());
}
- client.handleTooltipEvent(event, getTabsheet(), getElement());
+ client.handleWidgetTooltipEvent(event, getTabsheet(), getElement());
}
public Tab getTab() {
return tab;
}
- @Override
- public void setWidth(String width) {
- super.setWidth(width);
- if (BrowserInfo.get().isIE7()) {
- /*
- * IE7 apparently has problems with calculating width for
- * floated elements inside a DIV with padding. Set the width
- * explicitly for the caption.
- */
- fixTextWidth();
- }
- }
-
- private void fixTextWidth() {
- Element captionText = getTextElement();
- if (captionText == null) {
- return;
- }
-
- int captionWidth = Util.getRequiredWidth(captionText);
- int scrollWidth = captionText.getScrollWidth();
- if (scrollWidth > captionWidth) {
- captionWidth = scrollWidth;
- }
- captionText.getStyle().setPropertyPx("width", captionWidth);
- }
-
public void setClosable(boolean closable) {
this.closable = closable;
if (closable && closeButton == null) {
@@ -494,7 +470,7 @@ public class VTabsheet extends VTabsheetBase {
// Can't use "style" as it's already in use
public static final String TAB_STYLE_NAME = "tabstyle";
- private final Element tabs; // tabbar and 'scroller' container
+ final Element tabs; // tabbar and 'scroller' container
private final Element scroller; // tab-scroller element
private final Element scrollerNext; // tab-scroller next button element
private final Element scrollerPrev; // tab-scroller prev button element
@@ -505,15 +481,15 @@ public class VTabsheet extends VTabsheetBase {
private int scrollerIndex = 0;
private final TabBar tb = new TabBar(this);
- private final VTabsheetPanel tp = new VTabsheetPanel();
+ final VTabsheetPanel tp = new VTabsheetPanel();
private final Element contentNode, deco;
private String height;
private String width;
- private boolean waitingForResponse;
+ boolean waitingForResponse;
- private final RenderInformation renderInformation = new RenderInformation();
+ final RenderInformation renderInformation = new RenderInformation();
/**
* Previous visible widget is set invisible with CSS (not display: none, but
@@ -522,7 +498,7 @@ public class VTabsheet extends VTabsheetBase {
*/
private Widget previousVisibleWidget;
- private boolean rendering = false;
+ boolean rendering = false;
private String currentStyle;
@@ -570,11 +546,11 @@ public class VTabsheet extends VTabsheetBase {
client.updateVariable(id, "close", tabKeys.get(tabIndex), true);
}
- private boolean isDynamicWidth() {
+ boolean isDynamicWidth() {
return width == null || width.equals("");
}
- private boolean isDynamicHeight() {
+ boolean isDynamicHeight() {
return height == null || height.equals("");
}
@@ -658,60 +634,7 @@ public class VTabsheet extends VTabsheetBase {
return scrollerIndex > index;
}
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- rendering = true;
-
- if (!uidl.getBooleanAttribute("cached")) {
- // Handle stylename changes before generics (might affect size
- // calculations)
- handleStyleNames(uidl);
- }
-
- super.updateFromUIDL(uidl, client);
- if (cachedUpdate) {
- rendering = false;
- return;
- }
-
- // tabs; push or not
- if (!isDynamicWidth()) {
- // FIXME: This makes tab sheet tabs go to 1px width on every update
- // and then back to original width
- // update width later, in updateTabScroller();
- DOM.setStyleAttribute(tabs, "width", "1px");
- DOM.setStyleAttribute(tabs, "overflow", "hidden");
- } else {
- showAllTabs();
- DOM.setStyleAttribute(tabs, "width", "");
- DOM.setStyleAttribute(tabs, "overflow", "visible");
- updateDynamicWidth();
- }
-
- if (!isDynamicHeight()) {
- // Must update height after the styles have been set
- updateContentNodeHeight();
- updateOpenTabSize();
- }
-
- iLayout();
-
- // Re run relative size update to ensure optimal scrollbars
- // TODO isolate to situation that visible tab has undefined height
- try {
- client.handleComponentRelativeSize(tp.getWidget(tp
- .getVisibleWidget()));
- } catch (Exception e) {
- // Ignore, most likely empty tabsheet
- }
-
- renderInformation.updateSize(getElement());
-
- waitingForResponse = false;
- rendering = false;
- }
-
- private void handleStyleNames(UIDL uidl) {
+ void handleStyleNames(UIDL uidl) {
// Add proper stylenames for all elements (easier to prevent unwanted
// style inheritance)
if (uidl.hasAttribute("style")) {
@@ -753,7 +676,7 @@ public class VTabsheet extends VTabsheetBase {
}
}
- private void updateDynamicWidth() {
+ void updateDynamicWidth() {
// Find width consumed by tabs
TableCellElement spacerCell = ((TableElement) tb.getElement().cast())
.getRows().getItem(0).getCells().getItem(tb.getTabCount());
@@ -830,22 +753,24 @@ public class VTabsheet extends VTabsheetBase {
tab.recalculateCaptionWidth();
UIDL tabContentUIDL = null;
- Paintable tabContent = null;
+ VPaintableWidget tabContentPaintable = null;
+ Widget tabContentWidget = null;
if (tabUidl.getChildCount() > 0) {
tabContentUIDL = tabUidl.getChildUIDL(0);
- tabContent = client.getPaintable(tabContentUIDL);
+ tabContentPaintable = client.getPaintable(tabContentUIDL);
+ tabContentWidget = tabContentPaintable.getWidgetForPaintable();
}
- if (tabContent != null) {
+ if (tabContentPaintable != null) {
/* This is a tab with content information */
- int oldIndex = tp.getWidgetIndex((Widget) tabContent);
+ int oldIndex = tp.getWidgetIndex(tabContentWidget);
if (oldIndex != -1 && oldIndex != index) {
/*
* The tab has previously been rendered in another position so
* we must move the cached content to correct position
*/
- tp.insert((Widget) tabContent, index);
+ tp.insert(tabContentWidget, index);
}
} else {
/* A tab whose content has not yet been loaded */
@@ -869,10 +794,10 @@ public class VTabsheet extends VTabsheetBase {
} else {
if (tabContentUIDL != null) {
// updating a drawn child on hidden tab
- if (tp.getWidgetIndex((Widget) tabContent) < 0) {
- tp.insert((Widget) tabContent, index);
+ if (tp.getWidgetIndex(tabContentWidget) < 0) {
+ tp.insert(tabContentWidget, index);
}
- tabContent.updateFromUIDL(tabContentUIDL, client);
+ tabContentPaintable.updateFromUIDL(tabContentUIDL, client);
} else if (tp.getWidgetCount() <= index) {
tp.add(new PlaceHolder());
}
@@ -895,30 +820,32 @@ public class VTabsheet extends VTabsheetBase {
}
private void renderContent(final UIDL contentUIDL) {
- final Paintable content = client.getPaintable(contentUIDL);
+ final VPaintableWidget content = client.getPaintable(contentUIDL);
if (tp.getWidgetCount() > activeTabIndex) {
Widget old = tp.getWidget(activeTabIndex);
if (old != content) {
tp.remove(activeTabIndex);
- if (old instanceof Paintable) {
- client.unregisterPaintable((Paintable) old);
+ VPaintableMap paintableMap = VPaintableMap.get(client);
+ if (paintableMap.isPaintable(old)) {
+ paintableMap.unregisterPaintable(paintableMap
+ .getPaintable(old));
}
- tp.insert((Widget) content, activeTabIndex);
+ tp.insert(content.getWidgetForPaintable(), activeTabIndex);
}
} else {
- tp.add((Widget) content);
+ tp.add(content.getWidgetForPaintable());
}
tp.showWidget(activeTabIndex);
VTabsheet.this.iLayout();
- (content).updateFromUIDL(contentUIDL, client);
+ content.updateFromUIDL(contentUIDL, client);
/*
* The size of a cached, relative sized component must be updated to
* report correct size to updateOpenTabSize().
*/
if (contentUIDL.getBooleanAttribute("cached")) {
- client.handleComponentRelativeSize((Widget) content);
+ client.handleComponentRelativeSize(content.getWidgetForPaintable());
}
updateOpenTabSize();
VTabsheet.this.removeStyleDependentName("loading");
@@ -944,7 +871,7 @@ public class VTabsheet extends VTabsheetBase {
}
}
- private void updateContentNodeHeight() {
+ void updateContentNodeHeight() {
if (height != null && !"".equals(height)) {
int contentHeight = getOffsetHeight();
contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight");
@@ -1011,7 +938,7 @@ public class VTabsheet extends VTabsheetBase {
* position: absolute (to work around a firefox flickering bug) we must keep
* this up-to-date by hand.
*/
- private void updateOpenTabSize() {
+ void updateOpenTabSize() {
/*
* The overflow=auto element must have a height specified, otherwise it
* will be just as high as the contents and no scrollbars will appear
@@ -1087,7 +1014,7 @@ public class VTabsheet extends VTabsheetBase {
}
- private void showAllTabs() {
+ void showAllTabs() {
scrollerIndex = tb.getFirstVisibleTab();
for (int i = 0; i < tb.getTabCount(); i++) {
Tab t = tb.getTab(i);
@@ -1119,7 +1046,7 @@ public class VTabsheet extends VTabsheetBase {
}
@Override
- protected Iterator getPaintableIterator() {
+ protected Iterator<Widget> getWidgetIterator() {
return tp.iterator();
}
@@ -1135,19 +1062,15 @@ public class VTabsheet extends VTabsheetBase {
tp.replaceComponent(oldComponent, newComponent);
}
- public void updateCaption(Paintable component, UIDL uidl) {
- /* Tabsheet does not render its children's captions */
- }
-
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
if (!isDynamicHeight() && !isDynamicWidth()) {
/*
* If the height and width has been specified for this container the
* child components cannot make the size of the layout change
*/
// layout size change may affect its available space (scrollbars)
- for (Paintable paintable : child) {
- client.handleComponentRelativeSize((Widget) paintable);
+ for (Widget widget : children) {
+ client.handleComponentRelativeSize(widget);
}
return true;
}
@@ -1195,9 +1118,10 @@ public class VTabsheet extends VTabsheetBase {
}
@Override
- protected Paintable getTab(int index) {
+ protected VPaintableWidget getTab(int index) {
if (tp.getWidgetCount() > index) {
- return (Paintable) tp.getWidget(index);
+ Widget widget = tp.getWidget(index);
+ return VPaintableMap.get(client).getPaintable(widget);
}
return null;
}
@@ -1214,4 +1138,7 @@ public class VTabsheet extends VTabsheetBase {
}
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java
index 7304f62f41..271aed1859 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java
@@ -13,8 +13,8 @@ import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
abstract class VTabsheetBase extends ComplexPanel implements Container {
@@ -33,78 +33,6 @@ abstract class VTabsheetBase extends ComplexPanel implements Container {
setStyleName(classname);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
-
- // Ensure correct implementation
- cachedUpdate = client.updateComponent(this, uidl, true);
- if (cachedUpdate) {
- return;
- }
-
- // Update member references
- id = uidl.getId();
- disabled = uidl.hasAttribute("disabled");
-
- // Render content
- final UIDL tabs = uidl.getChildUIDL(0);
-
- // Paintables in the TabSheet before update
- ArrayList<Object> oldPaintables = new ArrayList<Object>();
- for (Iterator<Object> iterator = getPaintableIterator(); iterator
- .hasNext();) {
- oldPaintables.add(iterator.next());
- }
-
- // Clear previous values
- tabKeys.clear();
- disabledTabKeys.clear();
-
- int index = 0;
- for (final Iterator<Object> it = tabs.getChildIterator(); it.hasNext();) {
- final UIDL tab = (UIDL) it.next();
- final String key = tab.getStringAttribute("key");
- final boolean selected = tab.getBooleanAttribute("selected");
- final boolean hidden = tab.getBooleanAttribute("hidden");
-
- if (tab.getBooleanAttribute("disabled")) {
- disabledTabKeys.add(key);
- }
-
- tabKeys.add(key);
-
- if (selected) {
- activeTabIndex = index;
- }
- renderTab(tab, index, selected, hidden);
- index++;
- }
-
- int tabCount = getTabCount();
- while (tabCount-- > index) {
- removeTab(index);
- }
-
- for (int i = 0; i < getTabCount(); i++) {
- Paintable p = getTab(i);
- oldPaintables.remove(p);
- }
-
- // Perform unregister for any paintables removed during update
- for (Iterator<Object> iterator = oldPaintables.iterator(); iterator
- .hasNext();) {
- Object oldPaintable = iterator.next();
- if (oldPaintable instanceof Paintable) {
- Widget w = (Widget) oldPaintable;
- if (w.isAttached()) {
- w.removeFromParent();
- }
- client.unregisterPaintable((Paintable) oldPaintable);
- }
- }
-
- }
-
/**
* @return a list of currently shown Paintables
*
@@ -112,7 +40,7 @@ abstract class VTabsheetBase extends ComplexPanel implements Container {
* {@link #updateFromUIDL(UIDL, ApplicationConnection)} checks if
* instanceof Paintable. Therefore set to <Object>
*/
- abstract protected Iterator<Object> getPaintableIterator();
+ abstract protected Iterator<Widget> getWidgetIterator();
/**
* Clears current tabs and contents
@@ -143,7 +71,7 @@ abstract class VTabsheetBase extends ComplexPanel implements Container {
* Implement in extending classes. This method should return the Paintable
* corresponding to the given index.
*/
- protected abstract Paintable getTab(int index);
+ protected abstract VPaintableWidget getTab(int index);
/**
* Implement in extending classes. This method should remove the rendered
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBasePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBasePaintable.java
new file mode 100644
index 0000000000..ec3b02de97
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBasePaintable.java
@@ -0,0 +1,96 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public abstract class VTabsheetBasePaintable extends
+ VAbstractPaintableWidgetContainer {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().client = client;
+
+ // Ensure correct implementation
+ getWidgetForPaintable().cachedUpdate = client.updateComponent(this,
+ uidl, true);
+ if (getWidgetForPaintable().cachedUpdate) {
+ return;
+ }
+
+ // Update member references
+ getWidgetForPaintable().id = uidl.getId();
+ getWidgetForPaintable().disabled = uidl.hasAttribute("disabled");
+
+ // Render content
+ final UIDL tabs = uidl.getChildUIDL(0);
+
+ // Paintables in the TabSheet before update
+ ArrayList<Widget> oldWidgets = new ArrayList<Widget>();
+ for (Iterator<Widget> iterator = getWidgetForPaintable()
+ .getWidgetIterator(); iterator.hasNext();) {
+ oldWidgets.add(iterator.next());
+ }
+
+ // Clear previous values
+ getWidgetForPaintable().tabKeys.clear();
+ getWidgetForPaintable().disabledTabKeys.clear();
+
+ int index = 0;
+ for (final Iterator<Object> it = tabs.getChildIterator(); it.hasNext();) {
+ final UIDL tab = (UIDL) it.next();
+ final String key = tab.getStringAttribute("key");
+ final boolean selected = tab.getBooleanAttribute("selected");
+ final boolean hidden = tab.getBooleanAttribute("hidden");
+
+ if (tab.getBooleanAttribute("disabled")) {
+ getWidgetForPaintable().disabledTabKeys.add(key);
+ }
+
+ getWidgetForPaintable().tabKeys.add(key);
+
+ if (selected) {
+ getWidgetForPaintable().activeTabIndex = index;
+ }
+ getWidgetForPaintable().renderTab(tab, index, selected, hidden);
+ index++;
+ }
+
+ int tabCount = getWidgetForPaintable().getTabCount();
+ while (tabCount-- > index) {
+ getWidgetForPaintable().removeTab(index);
+ }
+
+ for (int i = 0; i < getWidgetForPaintable().getTabCount(); i++) {
+ VPaintableWidget p = getWidgetForPaintable().getTab(i);
+ // During the initial rendering the paintable might be null (this is
+ // weird...)
+ if (p != null) {
+ oldWidgets.remove(p.getWidgetForPaintable());
+ }
+ }
+
+ // Perform unregister for any paintables removed during update
+ for (Iterator<Widget> iterator = oldWidgets.iterator(); iterator
+ .hasNext();) {
+ Widget oldWidget = iterator.next();
+ VPaintableWidget oldPaintable = VPaintableMap.get(client)
+ .getPaintable(oldWidget);
+ if (oldWidget.isAttached()) {
+ oldWidget.removeFromParent();
+ }
+ VPaintableMap.get(client).unregisterPaintable(oldPaintable);
+ }
+
+ }
+
+ @Override
+ public VTabsheetBase getWidgetForPaintable() {
+ return (VTabsheetBase) super.getWidgetForPaintable();
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPaintable.java
new file mode 100644
index 0000000000..4bd91683d6
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPaintable.java
@@ -0,0 +1,82 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VTabsheetPaintable extends VTabsheetBasePaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+
+ if (!uidl.getBooleanAttribute("cached")) {
+ // Handle stylename changes before generics (might affect size
+ // calculations)
+ getWidgetForPaintable().handleStyleNames(uidl);
+ }
+
+ super.updateFromUIDL(uidl, client);
+ if (getWidgetForPaintable().cachedUpdate) {
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ // tabs; push or not
+ if (!getWidgetForPaintable().isDynamicWidth()) {
+ // FIXME: This makes tab sheet tabs go to 1px width on every update
+ // and then back to original width
+ // update width later, in updateTabScroller();
+ DOM.setStyleAttribute(getWidgetForPaintable().tabs, "width", "1px");
+ DOM.setStyleAttribute(getWidgetForPaintable().tabs, "overflow",
+ "hidden");
+ } else {
+ getWidgetForPaintable().showAllTabs();
+ DOM.setStyleAttribute(getWidgetForPaintable().tabs, "width", "");
+ DOM.setStyleAttribute(getWidgetForPaintable().tabs, "overflow",
+ "visible");
+ getWidgetForPaintable().updateDynamicWidth();
+ }
+
+ if (!getWidgetForPaintable().isDynamicHeight()) {
+ // Must update height after the styles have been set
+ getWidgetForPaintable().updateContentNodeHeight();
+ getWidgetForPaintable().updateOpenTabSize();
+ }
+
+ getWidgetForPaintable().iLayout();
+
+ // Re run relative size update to ensure optimal scrollbars
+ // TODO isolate to situation that visible tab has undefined height
+ try {
+ client.handleComponentRelativeSize(getWidgetForPaintable().tp
+ .getWidget(getWidgetForPaintable().tp.getVisibleWidget()));
+ } catch (Exception e) {
+ // Ignore, most likely empty tabsheet
+ }
+
+ getWidgetForPaintable().renderInformation
+ .updateSize(getWidgetForPaintable().getElement());
+
+ getWidgetForPaintable().waitingForResponse = false;
+ getWidgetForPaintable().rendering = false;
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VTabsheet.class);
+ }
+
+ @Override
+ public VTabsheet getWidgetForPaintable() {
+ return (VTabsheet) super.getWidgetForPaintable();
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ /* Tabsheet does not render its children's captions */
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java
index c6107e3b0e..2c8ed24693 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java
@@ -9,8 +9,6 @@ import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.UIDL;
/**
* This class represents a multiline textfield (textarea).
@@ -29,20 +27,6 @@ public class VTextArea extends VTextField {
setStyleName(CLASSNAME);
}
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // Call parent renderer explicitly
- super.updateFromUIDL(uidl, client);
-
- if (uidl.hasAttribute("rows")) {
- setRows(uidl.getIntAttribute("rows"));
- }
-
- if (getMaxLength() >= 0) {
- sinkEvents(Event.ONKEYUP);
- }
- }
-
public void setRows(int rows) {
setRows(getElement(), rows);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextAreaPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTextAreaPaintable.java
new file mode 100644
index 0000000000..3c21a4ab2f
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextAreaPaintable.java
@@ -0,0 +1,38 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VTextAreaPaintable extends VTextFieldPaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Call parent renderer explicitly
+ super.updateFromUIDL(uidl, client);
+
+ if (uidl.hasAttribute("rows")) {
+ getWidgetForPaintable().setRows(uidl.getIntAttribute("rows"));
+ }
+
+ if (getWidgetForPaintable().getMaxLength() >= 0) {
+ getWidgetForPaintable().sinkEvents(Event.ONKEYUP);
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VTextArea.class);
+ }
+
+ @Override
+ public VTextArea getWidgetForPaintable() {
+ return (VTextArea) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
index 44ee7c11df..80b27e6c8c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
@@ -4,7 +4,6 @@
package com.vaadin.terminal.gwt.client.ui;
-import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -15,7 +14,6 @@ import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
-import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -24,11 +22,8 @@ import com.google.gwt.user.client.ui.TextBoxBase;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
/**
* This class represents a basic text input field with one row.
@@ -36,9 +31,8 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutAct
* @author Vaadin Ltd.
*
*/
-public class VTextField extends TextBoxBase implements Paintable, Field,
- ChangeHandler, FocusHandler, BlurHandler, BeforeShortcutActionListener,
- KeyDownHandler {
+public class VTextField extends TextBoxBase implements Field, ChangeHandler,
+ FocusHandler, BlurHandler, KeyDownHandler {
public static final String VAR_CUR_TEXT = "curText";
@@ -52,11 +46,11 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
*/
public static final String CLASSNAME_FOCUS = "focus";
- protected String id;
+ protected String paintableId;
protected ApplicationConnection client;
- private String valueBeforeEdit = null;
+ protected String valueBeforeEdit = null;
/**
* Set to false if a text change event has been sent since the last value
@@ -65,20 +59,20 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
*/
private boolean valueBeforeEditIsSynced = true;
- private boolean immediate = false;
+ protected boolean immediate = false;
private int extraHorizontalPixels = -1;
private int extraVerticalPixels = -1;
private int maxLength = -1;
private static final String CLASSNAME_PROMPT = "prompt";
- private static final String ATTR_INPUTPROMPT = "prompt";
+ protected static final String ATTR_INPUTPROMPT = "prompt";
public static final String ATTR_TEXTCHANGE_TIMEOUT = "iet";
public static final String VAR_CURSOR = "c";
public static final String ATTR_TEXTCHANGE_EVENTMODE = "iem";
- private static final String TEXTCHANGE_MODE_EAGER = "EAGER";
+ protected static final String TEXTCHANGE_MODE_EAGER = "EAGER";
private static final String TEXTCHANGE_MODE_TIMEOUT = "TIMEOUT";
- private String inputPrompt = null;
+ protected String inputPrompt = null;
private boolean prompting = false;
private int lastCursorPos = -1;
private boolean wordwrap = true;
@@ -89,12 +83,6 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
protected VTextField(Element node) {
super(node);
- if (BrowserInfo.get().getIEVersion() > 0
- && BrowserInfo.get().getIEVersion() < 8) {
- // Fixes IE margin problem (#2058)
- DOM.setStyleAttribute(node, "marginTop", "-1px");
- DOM.setStyleAttribute(node, "marginBottom", "-1px");
- }
setStyleName(CLASSNAME);
addChangeHandler(this);
if (BrowserInfo.get().isIE()) {
@@ -117,14 +105,14 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
* Eager polling for a change is bit dum and heavy operation, so I guess we
* should first try to survive without.
*/
- private static final int TEXTCHANGE_EVENTS = Event.ONPASTE
+ protected static final int TEXTCHANGE_EVENTS = Event.ONPASTE
| Event.KEYEVENTS | Event.ONMOUSEUP;
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (client != null) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
if (listenTextChangeEvents
@@ -163,7 +151,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
client.sendPendingVariableChanges();
} else {
// Default case - just send an immediate text change message
- client.updateVariable(id, VAR_CUR_TEXT, text, true);
+ client.updateVariable(paintableId, VAR_CUR_TEXT, text, true);
// Shouldn't investigate valueBeforeEdit to avoid duplicate text
// change events as the states are not in sync any more
@@ -185,9 +173,9 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
}
};
private boolean scheduled = false;
- private boolean listenTextChangeEvents;
- private String textChangeEventMode;
- private int textChangeEventTimeout;
+ protected boolean listenTextChangeEvents;
+ protected String textChangeEventMode;
+ protected int textChangeEventTimeout;
private void deferTextChangeEvent() {
if (textChangeEventMode.equals(TEXTCHANGE_MODE_TIMEOUT) && scheduled) {
@@ -220,129 +208,19 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
super.setReadOnly(readOnly);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
- id = uidl.getId();
-
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- if (uidl.getBooleanAttribute("readonly")) {
- setReadOnly(true);
- } else {
- setReadOnly(false);
- }
-
- inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
-
- setMaxLength(uidl.hasAttribute("maxLength") ? uidl
- .getIntAttribute("maxLength") : -1);
-
- immediate = uidl.getBooleanAttribute("immediate");
-
- listenTextChangeEvents = client.hasEventListeners(this, "ie");
- if (listenTextChangeEvents) {
- textChangeEventMode = uidl
- .getStringAttribute(ATTR_TEXTCHANGE_EVENTMODE);
- if (textChangeEventMode.equals(TEXTCHANGE_MODE_EAGER)) {
- textChangeEventTimeout = 1;
- } else {
- textChangeEventTimeout = uidl
- .getIntAttribute(ATTR_TEXTCHANGE_TIMEOUT);
- if (textChangeEventTimeout < 1) {
- // Sanitize and allow lazy/timeout with timeout set to 0 to
- // work as eager
- textChangeEventTimeout = 1;
- }
- }
- sinkEvents(TEXTCHANGE_EVENTS);
- attachCutEventListener(getElement());
- }
-
- if (uidl.hasAttribute("cols")) {
- setColumns(new Integer(uidl.getStringAttribute("cols")).intValue());
- }
-
- final String text = uidl.getStringVariable("text");
-
- /*
- * We skip the text content update if field has been repainted, but text
- * has not been changed. Additional sanity check verifies there is no
- * change in the que (in which case we count more on the server side
- * value).
- */
- if (!(uidl.getBooleanAttribute(ATTR_NO_VALUE_CHANGE_BETWEEN_PAINTS)
- && valueBeforeEdit != null && text.equals(valueBeforeEdit))) {
- updateFieldContent(text);
- }
-
- if (uidl.hasAttribute("selpos")) {
- final int pos = uidl.getIntAttribute("selpos");
- final int length = uidl.getIntAttribute("sellen");
- /*
- * Gecko defers setting the text so we need to defer the selection.
- */
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- setSelectionRange(pos, length);
- }
- });
- }
-
- // Here for backward compatibility; to be moved to TextArea.
- // Optimization: server does not send attribute for the default 'true'
- // state.
- if (uidl.hasAttribute("wordwrap")
- && uidl.getBooleanAttribute("wordwrap") == false) {
- setWordwrap(false);
- } else {
- setWordwrap(true);
- }
- }
-
- private void updateFieldContent(final String text) {
+ protected void updateFieldContent(final String text) {
setPrompting(inputPrompt != null && focusedTextField != this
&& (text.equals("")));
- if (BrowserInfo.get().isFF3()) {
- /*
- * Firefox 3 is really sluggish when updating input attached to dom.
- * Some optimizations seems to work much better in Firefox3 if we
- * update the actual content lazily when the rest of the DOM has
- * stabilized. In tests, about ten times better performance is
- * achieved with this optimization. See for eg. #2898
- */
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- String fieldValue;
- if (prompting) {
- fieldValue = isReadOnly() ? "" : inputPrompt;
- addStyleDependentName(CLASSNAME_PROMPT);
- } else {
- fieldValue = text;
- removeStyleDependentName(CLASSNAME_PROMPT);
- }
- /*
- * Avoid resetting the old value. Prevents cursor flickering
- * which then again happens due to this Gecko hack.
- */
- if (!getText().equals(fieldValue)) {
- setText(fieldValue);
- }
- }
- });
+ String fieldValue;
+ if (prompting) {
+ fieldValue = isReadOnly() ? "" : inputPrompt;
+ addStyleDependentName(CLASSNAME_PROMPT);
} else {
- String fieldValue;
- if (prompting) {
- fieldValue = isReadOnly() ? "" : inputPrompt;
- addStyleDependentName(CLASSNAME_PROMPT);
- } else {
- fieldValue = text;
- removeStyleDependentName(CLASSNAME_PROMPT);
- }
- setText(fieldValue);
+ fieldValue = text;
+ removeStyleDependentName(CLASSNAME_PROMPT);
}
+ setText(fieldValue);
lastTextChangeString = valueBeforeEdit = text;
valueBeforeEditIsSynced = true;
@@ -384,7 +262,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
}
}
- private void setMaxLength(int newMaxLength) {
+ protected void setMaxLength(int newMaxLength) {
if (newMaxLength >= 0) {
maxLength = newMaxLength;
if (getElement().getTagName().toLowerCase().equals("textarea")) {
@@ -420,20 +298,20 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
* true if the field was blurred
*/
public void valueChange(boolean blurred) {
- if (client != null && id != null) {
+ if (client != null && paintableId != null) {
boolean sendBlurEvent = false;
boolean sendValueChange = false;
- if (blurred && client.hasEventListeners(this, EventId.BLUR)) {
+ if (blurred && client.hasWidgetEventListeners(this, EventId.BLUR)) {
sendBlurEvent = true;
- client.updateVariable(id, EventId.BLUR, "", false);
+ client.updateVariable(paintableId, EventId.BLUR, "", false);
}
String newText = getText();
if (!prompting && newText != null
&& !newText.equals(valueBeforeEdit)) {
sendValueChange = immediate;
- client.updateVariable(id, "text", getText(), false);
+ client.updateVariable(paintableId, "text", getText(), false);
valueBeforeEdit = newText;
valueBeforeEditIsSynced = true;
}
@@ -466,7 +344,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
if (Util.isAttachedAndDisplayed(this)) {
int cursorPos = getCursorPos();
if (lastCursorPos != cursorPos) {
- client.updateVariable(id, VAR_CURSOR, cursorPos, false);
+ client.updateVariable(paintableId, VAR_CURSOR, cursorPos, false);
lastCursorPos = cursorPos;
return true;
}
@@ -488,14 +366,10 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
setText("");
removeStyleDependentName(CLASSNAME_PROMPT);
setPrompting(false);
- if (BrowserInfo.get().isIE6()) {
- // IE6 does not show the cursor when tabbing into the field
- setCursorPos(0);
- }
}
focusedTextField = this;
- if (client.hasEventListeners(this, EventId.FOCUS)) {
- client.updateVariable(client.getPid(this), EventId.FOCUS, "", true);
+ if (client.hasWidgetEventListeners(this, EventId.FOCUS)) {
+ client.updateVariable(paintableId, EventId.FOCUS, "", true);
}
}
@@ -606,10 +480,6 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
}
}
- public void onBeforeShortcutAction(Event e) {
- valueChange(false);
- }
-
// Here for backward compatibility; to be moved to TextArea
public void setWordwrap(boolean enabled) {
if (enabled == wordwrap) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextFieldPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTextFieldPaintable.java
new file mode 100644
index 0000000000..e3eecd5a09
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextFieldPaintable.java
@@ -0,0 +1,124 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
+
+public class VTextFieldPaintable extends VAbstractPaintableWidget implements
+ BeforeShortcutActionListener {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Save details
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getId();
+
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ if (uidl.getBooleanAttribute("readonly")) {
+ getWidgetForPaintable().setReadOnly(true);
+ } else {
+ getWidgetForPaintable().setReadOnly(false);
+ }
+
+ getWidgetForPaintable().inputPrompt = uidl
+ .getStringAttribute(VTextField.ATTR_INPUTPROMPT);
+
+ getWidgetForPaintable().setMaxLength(
+ uidl.hasAttribute("maxLength") ? uidl
+ .getIntAttribute("maxLength") : -1);
+
+ getWidgetForPaintable().immediate = uidl
+ .getBooleanAttribute("immediate");
+
+ getWidgetForPaintable().listenTextChangeEvents = client
+ .hasEventListeners(this, "ie");
+ if (getWidgetForPaintable().listenTextChangeEvents) {
+ getWidgetForPaintable().textChangeEventMode = uidl
+ .getStringAttribute(VTextField.ATTR_TEXTCHANGE_EVENTMODE);
+ if (getWidgetForPaintable().textChangeEventMode
+ .equals(VTextField.TEXTCHANGE_MODE_EAGER)) {
+ getWidgetForPaintable().textChangeEventTimeout = 1;
+ } else {
+ getWidgetForPaintable().textChangeEventTimeout = uidl
+ .getIntAttribute(VTextField.ATTR_TEXTCHANGE_TIMEOUT);
+ if (getWidgetForPaintable().textChangeEventTimeout < 1) {
+ // Sanitize and allow lazy/timeout with timeout set to 0 to
+ // work as eager
+ getWidgetForPaintable().textChangeEventTimeout = 1;
+ }
+ }
+ getWidgetForPaintable().sinkEvents(VTextField.TEXTCHANGE_EVENTS);
+ getWidgetForPaintable().attachCutEventListener(
+ getWidgetForPaintable().getElement());
+ }
+
+ if (uidl.hasAttribute("cols")) {
+ getWidgetForPaintable().setColumns(
+ new Integer(uidl.getStringAttribute("cols")).intValue());
+ }
+
+ final String text = uidl.getStringVariable("text");
+
+ /*
+ * We skip the text content update if field has been repainted, but text
+ * has not been changed. Additional sanity check verifies there is no
+ * change in the que (in which case we count more on the server side
+ * value).
+ */
+ if (!(uidl
+ .getBooleanAttribute(VTextField.ATTR_NO_VALUE_CHANGE_BETWEEN_PAINTS)
+ && getWidgetForPaintable().valueBeforeEdit != null && text
+ .equals(getWidgetForPaintable().valueBeforeEdit))) {
+ getWidgetForPaintable().updateFieldContent(text);
+ }
+
+ if (uidl.hasAttribute("selpos")) {
+ final int pos = uidl.getIntAttribute("selpos");
+ final int length = uidl.getIntAttribute("sellen");
+ /*
+ * Gecko defers setting the text so we need to defer the selection.
+ */
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ getWidgetForPaintable().setSelectionRange(pos, length);
+ }
+ });
+ }
+
+ // Here for backward compatibility; to be moved to TextArea.
+ // Optimization: server does not send attribute for the default 'true'
+ // state.
+ if (uidl.hasAttribute("wordwrap")
+ && uidl.getBooleanAttribute("wordwrap") == false) {
+ getWidgetForPaintable().setWordwrap(false);
+ } else {
+ getWidgetForPaintable().setWordwrap(true);
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VTextField.class);
+ }
+
+ @Override
+ public VTextField getWidgetForPaintable() {
+ return (VTextField) super.getWidgetForPaintable();
+ }
+
+ public void onBeforeShortcutAction(Event e) {
+ getWidgetForPaintable().valueChange(false);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
index 56cdf05ddb..bb808321b9 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
@@ -12,29 +12,24 @@ import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.TextBox;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
import com.vaadin.terminal.gwt.client.EventId;
import com.vaadin.terminal.gwt.client.Focusable;
import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;
import com.vaadin.terminal.gwt.client.LocaleService;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VConsole;
-public class VTextualDate extends VDateField implements Paintable, Field,
- ChangeHandler, ContainerResizedListener, Focusable, SubPartAware {
+public class VTextualDate extends VDateField implements Field, ChangeHandler,
+ ContainerResizedListener, Focusable, SubPartAware {
private static final String PARSE_ERROR_CLASSNAME = CLASSNAME
+ "-parseerror";
- private final TextBox text;
+ protected final TextBox text;
- private String formatStr;
+ protected String formatStr;
private String width;
@@ -42,11 +37,11 @@ public class VTextualDate extends VDateField implements Paintable, Field,
protected int fieldExtraWidth = -1;
- private boolean lenient;
+ protected boolean lenient;
private static final String CLASSNAME_PROMPT = "prompt";
- private static final String ATTR_INPUTPROMPT = "prompt";
- private String inputPrompt = "";
+ protected static final String ATTR_INPUTPROMPT = "prompt";
+ protected String inputPrompt = "";
private boolean prompting = false;
public VTextualDate() {
@@ -67,8 +62,8 @@ public class VTextualDate extends VDateField implements Paintable, Field,
setPrompting(false);
}
if (getClient() != null
- && getClient().hasEventListeners(VTextualDate.this,
- EventId.FOCUS)) {
+ && getClient().hasWidgetEventListeners(
+ VTextualDate.this, EventId.FOCUS)) {
getClient()
.updateVariable(getId(), EventId.FOCUS, "", true);
}
@@ -85,8 +80,8 @@ public class VTextualDate extends VDateField implements Paintable, Field,
text.setText(readonly ? "" : inputPrompt);
}
if (getClient() != null
- && getClient().hasEventListeners(VTextualDate.this,
- EventId.BLUR)) {
+ && getClient().hasWidgetEventListeners(
+ VTextualDate.this, EventId.BLUR)) {
getClient().updateVariable(getId(), EventId.BLUR, "", true);
}
}
@@ -94,37 +89,6 @@ public class VTextualDate extends VDateField implements Paintable, Field,
add(text);
}
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- int origRes = currentResolution;
- String oldLocale = currentLocale;
- super.updateFromUIDL(uidl, client);
- if (origRes != currentResolution || oldLocale != currentLocale) {
- // force recreating format string
- formatStr = null;
- }
- if (uidl.hasAttribute("format")) {
- formatStr = uidl.getStringAttribute("format");
- }
-
- inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
-
- lenient = !uidl.getBooleanAttribute("strict");
-
- buildDate();
- // not a FocusWidget -> needs own tabindex handling
- if (uidl.hasAttribute("tabindex")) {
- text.setTabIndex(uidl.getIntAttribute("tabindex"));
- }
-
- if (readonly) {
- text.addStyleDependentName("readonly");
- } else {
- text.removeStyleDependentName("readonly");
- }
-
- }
-
protected String getFormatString() {
if (formatStr == null) {
if (currentResolution == RESOLUTION_YEAR) {
@@ -148,9 +112,6 @@ public class VTextualDate extends VDateField implements Paintable, Field,
frmString += ":mm";
if (currentResolution >= RESOLUTION_SEC) {
frmString += ":ss";
- if (currentResolution >= RESOLUTION_MSEC) {
- frmString += ".SSS";
- }
}
}
if (dts.isTwelveHourClock()) {
@@ -300,10 +261,6 @@ public class VTextualDate extends VDateField implements Paintable, Field,
currentResolution == VDateField.RESOLUTION_SEC
&& immediate);
}
- if (currentResolution == VDateField.RESOLUTION_MSEC) {
- getClient().updateVariable(getId(), "msec",
- currentDate != null ? getMilliseconds() : -1, immediate);
- }
}
@@ -340,11 +297,8 @@ public class VTextualDate extends VDateField implements Paintable, Field,
@Override
public void setWidth(String newWidth) {
- if (!"".equals(newWidth) && (isUndefinedWidth() || !newWidth.equals(width))) {
- if (BrowserInfo.get().isIE6()) {
- // in IE6 cols ~ min-width
- DOM.setElementProperty(text.getElement(), "size", "1");
- }
+ if (!"".equals(newWidth)
+ && (isUndefinedWidth() || !newWidth.equals(width))) {
needLayout = true;
width = newWidth;
super.setWidth(width);
@@ -354,19 +308,15 @@ public class VTextualDate extends VDateField implements Paintable, Field,
}
} else {
if ("".equals(newWidth) && !isUndefinedWidth()) {
- // Changing from defined to undefined
- if (BrowserInfo.get().isIE6()) {
- // revert IE6 hack
- DOM.setElementProperty(text.getElement(), "size", "");
- }
super.setWidth("");
iLayout(true);
width = null;
}
}
}
+
protected boolean isUndefinedWidth() {
- return width == null || "".equals(width);
+ return width == null || "".equals(width);
}
/**
@@ -378,10 +328,6 @@ public class VTextualDate extends VDateField implements Paintable, Field,
if (fieldExtraWidth < 0) {
text.setWidth("0");
fieldExtraWidth = text.getOffsetWidth();
- if (BrowserInfo.get().isFF3()) {
- // Firefox somehow always leaves the INPUT element 2px wide
- fieldExtraWidth -= 2;
- }
}
return fieldExtraWidth;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextualDatePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTextualDatePaintable.java
new file mode 100644
index 0000000000..6a9da31269
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextualDatePaintable.java
@@ -0,0 +1,58 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VTextualDatePaintable extends VDateFieldPaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ int origRes = getWidgetForPaintable().currentResolution;
+ String oldLocale = getWidgetForPaintable().currentLocale;
+ super.updateFromUIDL(uidl, client);
+ if (origRes != getWidgetForPaintable().currentResolution
+ || oldLocale != getWidgetForPaintable().currentLocale) {
+ // force recreating format string
+ getWidgetForPaintable().formatStr = null;
+ }
+ if (uidl.hasAttribute("format")) {
+ getWidgetForPaintable().formatStr = uidl
+ .getStringAttribute("format");
+ }
+
+ getWidgetForPaintable().inputPrompt = uidl
+ .getStringAttribute(VTextualDate.ATTR_INPUTPROMPT);
+
+ getWidgetForPaintable().lenient = !uidl.getBooleanAttribute("strict");
+
+ getWidgetForPaintable().buildDate();
+ // not a FocusWidget -> needs own tabindex handling
+ if (uidl.hasAttribute("tabindex")) {
+ getWidgetForPaintable().text.setTabIndex(uidl
+ .getIntAttribute("tabindex"));
+ }
+
+ if (getWidgetForPaintable().readonly) {
+ getWidgetForPaintable().text.addStyleDependentName("readonly");
+ } else {
+ getWidgetForPaintable().text.removeStyleDependentName("readonly");
+ }
+
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VTextualDate.class);
+ }
+
+ @Override
+ public VTextualDate getWidgetForPaintable() {
+ return (VTextualDate) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/VTree.java
index 4344cec5f5..be337ae0cb 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTree.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTree.java
@@ -40,10 +40,10 @@ 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.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.TooltipInfo;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.VTooltip;
import com.vaadin.terminal.gwt.client.ui.dd.DDUtil;
import com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler;
@@ -58,9 +58,9 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
/**
*
*/
-public class VTree extends FocusElementPanel implements Paintable,
- VHasDropHandler, FocusHandler, BlurHandler, KeyPressHandler,
- KeyDownHandler, SubPartAware, ActionOwner {
+public class VTree extends FocusElementPanel implements VHasDropHandler,
+ FocusHandler, BlurHandler, KeyPressHandler, KeyDownHandler,
+ SubPartAware, ActionOwner {
public static final String CLASSNAME = "v-tree";
@@ -71,17 +71,17 @@ public class VTree extends FocusElementPanel implements Paintable,
private static final int CHARCODE_SPACE = 32;
- private final FlowPanel body = new FlowPanel();
+ final FlowPanel body = new FlowPanel();
- private Set<String> selectedIds = new HashSet<String>();
- private ApplicationConnection client;
- private String paintableId;
- private boolean selectable;
- private boolean isMultiselect;
+ Set<String> selectedIds = new HashSet<String>();
+ ApplicationConnection client;
+ String paintableId;
+ boolean selectable;
+ boolean isMultiselect;
private String currentMouseOverKey;
- private TreeNode lastSelection;
- private TreeNode focusedNode;
- private int multiSelectMode = MULTISELECT_MODE_DEFAULT;
+ TreeNode lastSelection;
+ TreeNode focusedNode;
+ int multiSelectMode = MULTISELECT_MODE_DEFAULT;
private final HashMap<String, TreeNode> keyToNode = new HashMap<String, TreeNode>();
@@ -91,23 +91,23 @@ public class VTree extends FocusElementPanel implements Paintable,
*/
private final HashMap<String, String> actionMap = new HashMap<String, String>();
- private boolean immediate;
+ boolean immediate;
- private boolean isNullSelectionAllowed = true;
+ boolean isNullSelectionAllowed = true;
- private boolean disabled = false;
+ boolean disabled = false;
- private boolean readonly;
+ boolean readonly;
- private boolean rendering;
+ boolean rendering;
private VAbstractDropHandler dropHandler;
- private int dragMode;
+ int dragMode;
private boolean selectionHasChanged = false;
- private String[] bodyActionKeys;
+ String[] bodyActionKeys;
public VLazyExecutor iconLoaded = new VLazyExecutor(50,
new ScheduledCommand() {
@@ -206,24 +206,6 @@ public class VTree extends FocusElementPanel implements Paintable,
}
}
- private void updateActionMap(UIDL c) {
- final Iterator<?> it = c.getChildIterator();
- while (it.hasNext()) {
- final UIDL action = (UIDL) it.next();
- final String key = action.getStringAttribute("key");
- final String caption = action.getStringAttribute("caption");
- actionMap.put(key + "_c", caption);
- if (action.hasAttribute("icon")) {
- // TODO need some uri handling ??
- actionMap.put(key + "_i", client.translateVaadinUri(action
- .getStringAttribute("icon")));
- } else {
- actionMap.remove(key + "_i");
- }
- }
-
- }
-
public String getActionCaption(String actionKey) {
return actionMap.get(actionKey + "_c");
}
@@ -232,99 +214,6 @@ public class VTree extends FocusElementPanel implements Paintable,
return actionMap.get(actionKey + "_i");
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // Ensure correct implementation and let container manage caption
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- rendering = true;
-
- this.client = client;
-
- if (uidl.hasAttribute("partialUpdate")) {
- handleUpdate(uidl);
- rendering = false;
- return;
- }
-
- paintableId = uidl.getId();
-
- immediate = uidl.hasAttribute("immediate");
-
- disabled = uidl.getBooleanAttribute("disabled");
- readonly = uidl.getBooleanAttribute("readonly");
-
- dragMode = uidl.hasAttribute("dragMode") ? uidl
- .getIntAttribute("dragMode") : 0;
-
- isNullSelectionAllowed = uidl.getBooleanAttribute("nullselect");
-
- if (uidl.hasAttribute("alb")) {
- bodyActionKeys = uidl.getStringArrayAttribute("alb");
- }
-
- body.clear();
- // clear out any references to nodes that no longer are attached
- keyToNode.clear();
- TreeNode childTree = null;
- UIDL childUidl = null;
- for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) {
- childUidl = (UIDL) i.next();
- if ("actions".equals(childUidl.getTag())) {
- updateActionMap(childUidl);
- continue;
- } else if ("-ac".equals(childUidl.getTag())) {
- updateDropHandler(childUidl);
- continue;
- }
- childTree = new TreeNode();
- if (childTree.ie6compatnode != null) {
- body.add(childTree);
- }
- childTree.updateFromUIDL(childUidl, client);
- if (childTree.ie6compatnode == null) {
- body.add(childTree);
- }
- childTree.addStyleDependentName("root");
- childTree.childNodeContainer.addStyleDependentName("root");
- }
- if (childTree != null && childUidl != null) {
- boolean leaf = !childUidl.getTag().equals("node");
- childTree.addStyleDependentName(leaf ? "leaf-last" : "last");
- childTree.childNodeContainer.addStyleDependentName("last");
- }
- final String selectMode = uidl.getStringAttribute("selectmode");
- selectable = !"none".equals(selectMode);
- isMultiselect = "multi".equals(selectMode);
-
- if (isMultiselect) {
- multiSelectMode = uidl.getIntAttribute("multiselectmode");
- }
-
- selectedIds = uidl.getStringArrayVariableAsSet("selected");
-
- // Update lastSelection and focusedNode to point to *actual* nodes again
- // after the old ones have been cleared from the body. This fixes focus
- // and keyboard navigation issues as described in #7057 and other
- // tickets.
- if (lastSelection != null) {
- lastSelection = keyToNode.get(lastSelection.key);
- }
- if (focusedNode != null) {
- setFocusedNode(keyToNode.get(focusedNode.key));
- }
-
- if (lastSelection == null && focusedNode == null
- && !selectedIds.isEmpty()) {
- setFocusedNode(keyToNode.get(selectedIds.iterator().next()));
- focusedNode.setFocused(false);
- }
-
- rendering = false;
-
- }
-
/**
* Returns the first root node of the tree or null if there are no root
* nodes.
@@ -371,7 +260,7 @@ public class VTree extends FocusElementPanel implements Paintable,
drag.getDropDetails().put("itemIdOver", currentMouseOverKey);
if (currentMouseOverKey != null) {
- TreeNode treeNode = keyToNode.get(currentMouseOverKey);
+ TreeNode treeNode = getNodeByKey(currentMouseOverKey);
VerticalDropLocation detail = treeNode.getDropDetail(drag
.getCurrentGwtEvent());
Boolean overTreeNode = null;
@@ -393,7 +282,7 @@ public class VTree extends FocusElementPanel implements Paintable,
return treeNode == null ? null : treeNode.key;
}
- private void updateDropHandler(UIDL childUidl) {
+ void updateDropHandler(UIDL childUidl) {
if (dropHandler == null) {
dropHandler = new VAbstractDropHandler() {
@@ -435,7 +324,7 @@ public class VTree extends FocusElementPanel implements Paintable,
.getDropDetails().get("detail");
if (curDetail == detail
&& newKey.equals(currentMouseOverKey)) {
- keyToNode.get(newKey).emphasis(detail);
+ getNodeByKey(newKey).emphasis(detail);
}
/*
* Else drag is already on a different
@@ -457,7 +346,7 @@ public class VTree extends FocusElementPanel implements Paintable,
private void cleanUp() {
if (currentMouseOverKey != null) {
- keyToNode.get(currentMouseOverKey).emphasis(null);
+ getNodeByKey(currentMouseOverKey).emphasis(null);
currentMouseOverKey = null;
}
}
@@ -469,8 +358,8 @@ public class VTree extends FocusElementPanel implements Paintable,
}
@Override
- public Paintable getPaintable() {
- return VTree.this;
+ public VPaintableWidget getPaintable() {
+ return VPaintableMap.get(client).getPaintable(VTree.this);
}
public ApplicationConnection getApplicationConnection() {
@@ -482,24 +371,12 @@ public class VTree extends FocusElementPanel implements Paintable,
dropHandler.updateAcceptRules(childUidl);
}
- private void handleUpdate(UIDL uidl) {
- final TreeNode rootNode = keyToNode.get(uidl
- .getStringAttribute("rootKey"));
- if (rootNode != null) {
- if (!rootNode.getState()) {
- // expanding node happened server side
- rootNode.setState(true, false);
- }
- rootNode.renderChildNodes(uidl.getChildIterator());
- }
- }
-
public void setSelected(TreeNode treeNode, boolean selected) {
if (selected) {
if (!isMultiselect) {
while (selectedIds.size() > 0) {
final String id = selectedIds.iterator().next();
- final TreeNode oldSelection = keyToNode.get(id);
+ final TreeNode oldSelection = getNodeByKey(id);
if (oldSelection != null) {
// can be null if the node is not visible (parent
// collapsed)
@@ -568,33 +445,26 @@ public class VTree extends FocusElementPanel implements Paintable,
public String key;
- private String[] actionKeys = null;
+ String[] actionKeys = null;
- private boolean childrenLoaded;
+ boolean childrenLoaded;
- private Element nodeCaptionDiv;
+ Element nodeCaptionDiv;
protected Element nodeCaptionSpan;
- private FlowPanel childNodeContainer;
+ FlowPanel childNodeContainer;
private boolean open;
private Icon icon;
- private Element ie6compatnode;
-
private Event mouseDownEvent;
private int cachedHeight = -1;
private boolean focused = false;
- /**
- * Track onload events as IE6 sends two
- */
- private boolean onloadHandled = false;
-
public TreeNode() {
constructDom();
sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS
@@ -692,11 +562,11 @@ public class VTree extends FocusElementPanel implements Paintable,
// always when clicking an item, focus it
setFocusedNode(this, false);
- if (!isIE6OrOpera()) {
+ if (!BrowserInfo.get().isOpera()) {
/*
* Ensure that the tree's focus element also gains focus
* (TreeNodes focus is faked using FocusElementPanel in browsers
- * other than IE6 and Opera).
+ * other than Opera).
*/
focus();
}
@@ -764,14 +634,7 @@ public class VTree extends FocusElementPanel implements Paintable,
final Element target = DOM.eventGetTarget(event);
if (type == Event.ONLOAD && target == icon.getElement()) {
- if (onloadHandled) {
- return;
- }
- if (BrowserInfo.get().isIE6()) {
- fixWidth();
- }
iconLoaded.trigger();
- onloadHandled = true;
}
if (disabled) {
@@ -779,20 +642,20 @@ public class VTree extends FocusElementPanel implements Paintable,
}
if (target == nodeCaptionSpan) {
- client.handleTooltipEvent(event, VTree.this, key);
+ client.handleWidgetTooltipEvent(event, VTree.this, key);
}
final boolean inCaption = target == nodeCaptionSpan
|| (icon != null && target == icon.getElement());
if (inCaption
- && client
- .hasEventListeners(VTree.this, ITEM_CLICK_EVENT_ID)
+ && client.hasWidgetEventListeners(VTree.this,
+ ITEM_CLICK_EVENT_ID)
&& (type == Event.ONDBLCLICK || type == Event.ONMOUSEUP)) {
fireClick(event);
}
if (type == Event.ONCLICK) {
- if (getElement() == target || ie6compatnode == target) {
+ if (getElement() == target) {
// state change
toggleState();
} else if (!readonly && inCaption) {
@@ -847,7 +710,8 @@ public class VTree extends FocusElementPanel implements Paintable,
if (mouseDownEvent != null) {
// start actual drag on slight move when mouse is down
VTransferable t = new VTransferable();
- t.setDragSource(VTree.this);
+ t.setDragSource(VPaintableMap.get(client).getPaintable(
+ VTree.this));
t.setData("itemId", key);
VDragEvent drag = VDragAndDropManager.get().startDrag(
t, mouseDownEvent, true);
@@ -878,7 +742,7 @@ public class VTree extends FocusElementPanel implements Paintable,
* previously modified field may contain dirty variables.
*/
if (!treeHasFocus) {
- if (isIE6OrOpera()) {
+ if (BrowserInfo.get().isOpera()) {
if (focusedNode == null) {
getNodeByKey(key).setFocused(true);
} else {
@@ -939,15 +803,6 @@ public class VTree extends FocusElementPanel implements Paintable,
protected void constructDom() {
addStyleName(CLASSNAME);
- // workaround for a very weird IE6 issue #1245
- if (BrowserInfo.get().isIE6()) {
- ie6compatnode = DOM.createDiv();
- setStyleName(ie6compatnode, CLASSNAME + "-ie6compatnode");
- DOM.setInnerText(ie6compatnode, " ");
- DOM.appendChild(getElement(), ie6compatnode);
-
- DOM.sinkEvents(ie6compatnode, Event.ONCLICK);
- }
nodeCaptionDiv = DOM.createDiv();
DOM.setElementProperty(nodeCaptionDiv, "className", CLASSNAME
@@ -959,7 +814,7 @@ public class VTree extends FocusElementPanel implements Paintable,
DOM.appendChild(nodeCaptionDiv, wrapper);
DOM.appendChild(wrapper, nodeCaptionSpan);
- if (isIE6OrOpera()) {
+ if (BrowserInfo.get().isOpera()) {
/*
* Focus the caption div of the node to get keyboard navigation
* to work without scrolling up or down when focusing a node.
@@ -972,76 +827,6 @@ public class VTree extends FocusElementPanel implements Paintable,
setWidget(childNodeContainer);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- setText(uidl.getStringAttribute("caption"));
- key = uidl.getStringAttribute("key");
-
- keyToNode.put(key, this);
-
- if (uidl.hasAttribute("al")) {
- actionKeys = uidl.getStringArrayAttribute("al");
- }
-
- if (uidl.getTag().equals("node")) {
- if (uidl.getChildCount() == 0) {
- childNodeContainer.setVisible(false);
- } else {
- renderChildNodes(uidl.getChildIterator());
- childrenLoaded = true;
- }
- } else {
- addStyleName(CLASSNAME + "-leaf");
- }
- if (uidl.hasAttribute("style")) {
- addStyleName(CLASSNAME + "-" + uidl.getStringAttribute("style"));
- Widget.setStyleName(nodeCaptionDiv, CLASSNAME + "-caption-"
- + uidl.getStringAttribute("style"), true);
- childNodeContainer.addStyleName(CLASSNAME + "-children-"
- + uidl.getStringAttribute("style"));
- }
-
- String description = uidl.getStringAttribute("descr");
- if (description != null && client != null) {
- // Set tooltip
- TooltipInfo info = new TooltipInfo(description);
- client.registerTooltip(VTree.this, key, info);
- } else {
- // Remove possible previous tooltip
- client.registerTooltip(VTree.this, key, null);
- }
-
- if (uidl.getBooleanAttribute("expanded") && !getState()) {
- setState(true, false);
- }
-
- if (uidl.getBooleanAttribute("selected")) {
- setSelected(true);
- // ensure that identifier is in selectedIds array (this may be a
- // partial update)
- selectedIds.add(key);
- }
-
- if (uidl.hasAttribute("icon")) {
- if (icon == null) {
- onloadHandled = false;
- icon = new Icon(client);
- DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv),
- icon.getElement(), nodeCaptionSpan);
- }
- icon.setUri(uidl.getStringAttribute("icon"));
- } else {
- if (icon != null) {
- DOM.removeChild(DOM.getFirstChild(nodeCaptionDiv),
- icon.getElement());
- icon = null;
- }
- }
-
- if (BrowserInfo.get().isIE6() && isAttached()) {
- fixWidth();
- }
- }
-
public boolean isLeaf() {
String[] styleNames = getStyleName().split(" ");
for (String styleName : styleNames) {
@@ -1052,7 +837,7 @@ public class VTree extends FocusElementPanel implements Paintable,
return false;
}
- private void setState(boolean state, boolean notifyServer) {
+ void setState(boolean state, boolean notifyServer) {
if (open == state) {
return;
}
@@ -1083,43 +868,14 @@ public class VTree extends FocusElementPanel implements Paintable,
}
}
- private boolean getState() {
+ boolean getState() {
return open;
}
- private void setText(String text) {
+ void setText(String text) {
DOM.setInnerText(nodeCaptionSpan, text);
}
- private void renderChildNodes(Iterator<?> i) {
- childNodeContainer.clear();
- childNodeContainer.setVisible(true);
- while (i.hasNext()) {
- final UIDL childUidl = (UIDL) i.next();
- // actions are in bit weird place, don't mix them with children,
- // but current node's actions
- if ("actions".equals(childUidl.getTag())) {
- updateActionMap(childUidl);
- continue;
- }
- final TreeNode childTree = new TreeNode();
- if (ie6compatnode != null) {
- childNodeContainer.add(childTree);
- }
- childTree.updateFromUIDL(childUidl, client);
- if (ie6compatnode == null) {
- childNodeContainer.add(childTree);
- }
- if (!i.hasNext()) {
- childTree
- .addStyleDependentName(childTree.isLeaf() ? "leaf-last"
- : "last");
- childTree.childNodeContainer.addStyleDependentName("last");
- }
- }
- childrenLoaded = true;
- }
-
public boolean isChildrenLoaded() {
return childrenLoaded;
}
@@ -1220,32 +976,6 @@ public class VTree extends FocusElementPanel implements Paintable,
}
/*
- * We need to fix the width of TreeNodes so that the float in
- * ie6compatNode does not wrap (see ticket #1245)
- */
- private void fixWidth() {
- nodeCaptionDiv.getStyle().setProperty("styleFloat", "left");
- nodeCaptionDiv.getStyle().setProperty("display", "inline");
- nodeCaptionDiv.getStyle().setProperty("marginLeft", "0");
- final int captionWidth = ie6compatnode.getOffsetWidth()
- + nodeCaptionDiv.getOffsetWidth();
- setWidth(captionWidth + "px");
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.client.ui.Widget#onAttach()
- */
- @Override
- public void onAttach() {
- super.onAttach();
- if (ie6compatnode != null) {
- fixWidth();
- }
- }
-
- /*
* (non-Javadoc)
*
* @see com.google.gwt.user.client.ui.Widget#onDetach()
@@ -1275,19 +1005,14 @@ public class VTree extends FocusElementPanel implements Paintable,
public void setFocused(boolean focused) {
if (!this.focused && focused) {
nodeCaptionDiv.addClassName(CLASSNAME_FOCUSED);
- if (BrowserInfo.get().isIE6()) {
- ie6compatnode.addClassName(CLASSNAME_FOCUSED);
- }
+
this.focused = focused;
- if (isIE6OrOpera()) {
+ if (BrowserInfo.get().isOpera()) {
nodeCaptionDiv.focus();
}
treeHasFocus = true;
} else if (this.focused && !focused) {
nodeCaptionDiv.removeClassName(CLASSNAME_FOCUSED);
- if (BrowserInfo.get().isIE6()) {
- ie6compatnode.removeClassName(CLASSNAME_FOCUSED);
- }
this.focused = focused;
treeHasFocus = false;
}
@@ -1300,6 +1025,34 @@ public class VTree extends FocusElementPanel implements Paintable,
Util.scrollIntoViewVertically(nodeCaptionDiv);
}
+ public void setIcon(String iconUrl) {
+ if (iconUrl != null) {
+ // Add icon if not present
+ if (icon == null) {
+ icon = new Icon(client);
+ DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv),
+ icon.getElement(), nodeCaptionSpan);
+ }
+ icon.setUri(iconUrl);
+ } else {
+ // Remove icon if present
+ if (icon != null) {
+ DOM.removeChild(DOM.getFirstChild(nodeCaptionDiv),
+ icon.getElement());
+ icon = null;
+ }
+ }
+ }
+
+ public void setNodeStyleName(String styleName) {
+ addStyleName(TreeNode.CLASSNAME + "-" + styleName);
+ setStyleName(nodeCaptionDiv, TreeNode.CLASSNAME + "-caption-"
+ + styleName, true);
+ childNodeContainer.addStyleName(TreeNode.CLASSNAME + "-children-"
+ + styleName);
+
+ }
+
}
public VDropHandler getDropHandler() {
@@ -2174,7 +1927,7 @@ public class VTree extends FocusElementPanel implements Paintable,
*/
public Element getSubPartElement(String subPart) {
if ("fe".equals(subPart)) {
- if (isIE6OrOpera() && focusedNode != null) {
+ if (BrowserInfo.get().isOpera() && focusedNode != null) {
return focusedNode.getElement();
}
return getFocusElement();
@@ -2206,11 +1959,7 @@ public class VTree extends FocusElementPanel implements Paintable,
}
if (expandCollapse) {
- if (treeNode.ie6compatnode != null) {
- return treeNode.ie6compatnode;
- } else {
- return treeNode.getElement();
- }
+ return treeNode.getElement();
} else {
return treeNode.nodeCaptionSpan;
}
@@ -2254,8 +2003,7 @@ public class VTree extends FocusElementPanel implements Paintable,
return null;
}
- if (subElement == treeNode.getElement()
- || subElement == treeNode.ie6compatnode) {
+ if (subElement == treeNode.getElement()) {
// Targets expand/collapse arrow
isExpandCollapse = true;
}
@@ -2317,7 +2065,22 @@ public class VTree extends FocusElementPanel implements Paintable,
}
}
- private boolean isIE6OrOpera() {
- return BrowserInfo.get().isIE6() || BrowserInfo.get().isOpera();
+ public void registerAction(String key, String caption, String iconUrl) {
+ actionMap.put(key + "_c", caption);
+ if (iconUrl != null) {
+ actionMap.put(key + "_i", iconUrl);
+ } else {
+ actionMap.remove(key + "_i");
+ }
+
+ }
+
+ public void registerNode(TreeNode treeNode) {
+ keyToNode.put(treeNode.key, treeNode);
}
+
+ public void clearNodeToKeyMap() {
+ keyToNode.clear();
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTreePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTreePaintable.java
new file mode 100644
index 0000000000..d7f8fffbd7
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTreePaintable.java
@@ -0,0 +1,228 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.TooltipInfo;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.VTree.TreeNode;
+
+public class VTreePaintable extends VAbstractPaintableWidget {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Ensure correct implementation and let container manage caption
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ getWidgetForPaintable().rendering = true;
+
+ getWidgetForPaintable().client = client;
+
+ if (uidl.hasAttribute("partialUpdate")) {
+ handleUpdate(uidl);
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ getWidgetForPaintable().paintableId = uidl.getId();
+
+ getWidgetForPaintable().immediate = uidl.hasAttribute("immediate");
+
+ getWidgetForPaintable().disabled = uidl.getBooleanAttribute("disabled");
+ getWidgetForPaintable().readonly = uidl.getBooleanAttribute("readonly");
+
+ getWidgetForPaintable().dragMode = uidl.hasAttribute("dragMode") ? uidl
+ .getIntAttribute("dragMode") : 0;
+
+ getWidgetForPaintable().isNullSelectionAllowed = uidl
+ .getBooleanAttribute("nullselect");
+
+ if (uidl.hasAttribute("alb")) {
+ getWidgetForPaintable().bodyActionKeys = uidl
+ .getStringArrayAttribute("alb");
+ }
+
+ getWidgetForPaintable().body.clear();
+ // clear out any references to nodes that no longer are attached
+ getWidgetForPaintable().clearNodeToKeyMap();
+ TreeNode childTree = null;
+ UIDL childUidl = null;
+ for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) {
+ childUidl = (UIDL) i.next();
+ if ("actions".equals(childUidl.getTag())) {
+ updateActionMap(childUidl);
+ continue;
+ } else if ("-ac".equals(childUidl.getTag())) {
+ getWidgetForPaintable().updateDropHandler(childUidl);
+ continue;
+ }
+ childTree = getWidgetForPaintable().new TreeNode();
+ updateNodeFromUIDL(childTree, childUidl);
+ getWidgetForPaintable().body.add(childTree);
+ childTree.addStyleDependentName("root");
+ childTree.childNodeContainer.addStyleDependentName("root");
+ }
+ if (childTree != null && childUidl != null) {
+ boolean leaf = !childUidl.getTag().equals("node");
+ childTree.addStyleDependentName(leaf ? "leaf-last" : "last");
+ childTree.childNodeContainer.addStyleDependentName("last");
+ }
+ final String selectMode = uidl.getStringAttribute("selectmode");
+ getWidgetForPaintable().selectable = !"none".equals(selectMode);
+ getWidgetForPaintable().isMultiselect = "multi".equals(selectMode);
+
+ if (getWidgetForPaintable().isMultiselect) {
+ getWidgetForPaintable().multiSelectMode = uidl
+ .getIntAttribute("multiselectmode");
+ }
+
+ getWidgetForPaintable().selectedIds = uidl
+ .getStringArrayVariableAsSet("selected");
+
+ // Update lastSelection and focusedNode to point to *actual* nodes again
+ // after the old ones have been cleared from the body. This fixes focus
+ // and keyboard navigation issues as described in #7057 and other
+ // tickets.
+ if (getWidgetForPaintable().lastSelection != null) {
+ getWidgetForPaintable().lastSelection = getWidgetForPaintable()
+ .getNodeByKey(getWidgetForPaintable().lastSelection.key);
+ }
+ if (getWidgetForPaintable().focusedNode != null) {
+ getWidgetForPaintable().setFocusedNode(
+ getWidgetForPaintable().getNodeByKey(
+ getWidgetForPaintable().focusedNode.key));
+ }
+
+ if (getWidgetForPaintable().lastSelection == null
+ && getWidgetForPaintable().focusedNode == null
+ && !getWidgetForPaintable().selectedIds.isEmpty()) {
+ getWidgetForPaintable().setFocusedNode(
+ getWidgetForPaintable().getNodeByKey(
+ getWidgetForPaintable().selectedIds.iterator()
+ .next()));
+ getWidgetForPaintable().focusedNode.setFocused(false);
+ }
+
+ getWidgetForPaintable().rendering = false;
+
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VTree.class);
+ }
+
+ @Override
+ public VTree getWidgetForPaintable() {
+ return (VTree) super.getWidgetForPaintable();
+ }
+
+ private void handleUpdate(UIDL uidl) {
+ final TreeNode rootNode = getWidgetForPaintable().getNodeByKey(
+ uidl.getStringAttribute("rootKey"));
+ if (rootNode != null) {
+ if (!rootNode.getState()) {
+ // expanding node happened server side
+ rootNode.setState(true, false);
+ }
+ renderChildNodes(rootNode, (Iterator) uidl.getChildIterator());
+ }
+ }
+
+ /**
+ * Registers action for the root and also for individual nodes
+ *
+ * @param uidl
+ */
+ private void updateActionMap(UIDL uidl) {
+ final Iterator<?> it = uidl.getChildIterator();
+ while (it.hasNext()) {
+ final UIDL action = (UIDL) it.next();
+ final String key = action.getStringAttribute("key");
+ final String caption = action.getStringAttribute("caption");
+ String iconUrl = null;
+ if (action.hasAttribute("icon")) {
+ iconUrl = getConnection().translateVaadinUri(
+ action.getStringAttribute("icon"));
+ }
+ getWidgetForPaintable().registerAction(key, caption, iconUrl);
+ }
+
+ }
+
+ public void updateNodeFromUIDL(TreeNode treeNode, UIDL uidl) {
+ String nodeKey = uidl.getStringAttribute("key");
+ treeNode.setText(uidl.getStringAttribute("caption"));
+ treeNode.key = nodeKey;
+
+ getWidgetForPaintable().registerNode(treeNode);
+
+ if (uidl.hasAttribute("al")) {
+ treeNode.actionKeys = uidl.getStringArrayAttribute("al");
+ }
+
+ if (uidl.getTag().equals("node")) {
+ if (uidl.getChildCount() == 0) {
+ treeNode.childNodeContainer.setVisible(false);
+ } else {
+ renderChildNodes(treeNode, (Iterator) uidl.getChildIterator());
+ treeNode.childrenLoaded = true;
+ }
+ } else {
+ treeNode.addStyleName(TreeNode.CLASSNAME + "-leaf");
+ }
+ if (uidl.hasAttribute("style")) {
+ treeNode.setNodeStyleName(uidl.getStringAttribute("style"));
+ }
+
+ String description = uidl.getStringAttribute("descr");
+ if (description != null && getConnection() != null) {
+ // Set tooltip
+ TooltipInfo info = new TooltipInfo(description);
+ getConnection().registerTooltip(this, nodeKey, info);
+ } else {
+ // Remove possible previous tooltip
+ getConnection().registerTooltip(this, nodeKey, null);
+ }
+
+ if (uidl.getBooleanAttribute("expanded") && !treeNode.getState()) {
+ treeNode.setState(true, false);
+ }
+
+ if (uidl.getBooleanAttribute("selected")) {
+ treeNode.setSelected(true);
+ // ensure that identifier is in selectedIds array (this may be a
+ // partial update)
+ getWidgetForPaintable().selectedIds.add(nodeKey);
+ }
+
+ treeNode.setIcon(uidl.getStringAttribute("icon"));
+ }
+
+ void renderChildNodes(TreeNode containerNode, Iterator<UIDL> i) {
+ containerNode.childNodeContainer.clear();
+ containerNode.childNodeContainer.setVisible(true);
+ while (i.hasNext()) {
+ final UIDL childUidl = i.next();
+ // actions are in bit weird place, don't mix them with children,
+ // but current node's actions
+ if ("actions".equals(childUidl.getTag())) {
+ updateActionMap(childUidl);
+ continue;
+ }
+ final TreeNode childTree = getWidgetForPaintable().new TreeNode();
+ updateNodeFromUIDL(childTree, childUidl);
+ containerNode.add(childTree);
+ if (!i.hasNext()) {
+ childTree
+ .addStyleDependentName(childTree.isLeaf() ? "leaf-last"
+ : "last");
+ childTree.childNodeContainer.addStyleDependentName("last");
+ }
+ }
+ containerNode.childrenLoaded = true;
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java b/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java
index 8e55400f31..0eddca0ed3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java
@@ -24,21 +24,19 @@ import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ComputedStyle;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow;
import com.vaadin.terminal.gwt.client.ui.VTreeTable.VTreeTableScrollBody.VTreeTableRow;
public class VTreeTable extends VScrollTable {
- private static class PendingNavigationEvent {
- private final int keycode;
- private final boolean ctrl;
- private final boolean shift;
+ static class PendingNavigationEvent {
+ final int keycode;
+ final boolean ctrl;
+ final boolean shift;
public PendingNavigationEvent(int keycode, boolean ctrl, boolean shift) {
this.keycode = keycode;
@@ -59,82 +57,14 @@ public class VTreeTable extends VScrollTable {
}
}
- public static final String ATTRIBUTE_HIERARCHY_COLUMN_INDEX = "hci";
- private boolean collapseRequest;
+ boolean collapseRequest;
private boolean selectionPending;
- private int colIndexOfHierarchy;
- private String collapsedRowKey;
- private VTreeTableScrollBody scrollBody;
- private boolean animationsEnabled;
- private LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTable.PendingNavigationEvent>();
- private boolean focusParentResponsePending;
-
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- FocusableScrollPanel widget = null;
- int scrollPosition = 0;
- if (collapseRequest) {
- widget = (FocusableScrollPanel) getWidget(1);
- scrollPosition = widget.getScrollPosition();
- }
- animationsEnabled = uidl.getBooleanAttribute("animate");
- colIndexOfHierarchy = uidl
- .hasAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) ? uidl
- .getIntAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) : 0;
- int oldTotalRows = getTotalRows();
- super.updateFromUIDL(uidl, client);
- if (collapseRequest) {
- if (collapsedRowKey != null && scrollBody != null) {
- VScrollTableRow row = getRenderedRowByKey(collapsedRowKey);
- if (row != null) {
- setRowFocus(row);
- focus();
- }
- }
-
- int scrollPosition2 = widget.getScrollPosition();
- if (scrollPosition != scrollPosition2) {
- widget.setScrollPosition(scrollPosition);
- }
-
- // check which rows are needed from the server and initiate a
- // deferred fetch
- onScroll(null);
- }
- // Recalculate table size if collapse request, or if page length is zero
- // (not sent by server) and row count changes (#7908).
- if (collapseRequest
- || (!uidl.hasAttribute("pagelength") && getTotalRows() != oldTotalRows)) {
- /*
- * Ensure that possibly removed/added scrollbars are considered.
- * Triggers row calculations, removes cached rows etc. Basically
- * cleans up state. Be careful if touching this, you will break
- * pageLength=0 if you remove this.
- */
- triggerLazyColumnAdjustment(true);
-
- collapseRequest = false;
- }
- if (uidl.hasAttribute("focusedRow")) {
- String key = uidl.getStringAttribute("focusedRow");
- setRowFocus(getRenderedRowByKey(key));
- focusParentResponsePending = false;
- } else if (uidl.hasAttribute("clearFocusPending")) {
- // Special case to detect a response to a focusParent request that
- // does not return any focusedRow because the selected node has no
- // parent
- focusParentResponsePending = false;
- }
-
- while (!collapseRequest && !focusParentResponsePending
- && !pendingNavigationEvents.isEmpty()) {
- // Keep replaying any queued events as long as we don't have any
- // potential content changes pending
- PendingNavigationEvent event = pendingNavigationEvents
- .removeFirst();
- handleNavigation(event.keycode, event.ctrl, event.shift);
- }
- }
+ int colIndexOfHierarchy;
+ String collapsedRowKey;
+ VTreeTableScrollBody scrollBody;
+ boolean animationsEnabled;
+ LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTable.PendingNavigationEvent>();
+ boolean focusParentResponsePending;
@Override
protected VScrollTableBody createScrollBody() {
@@ -169,7 +99,7 @@ public class VTreeTable extends VScrollTable {
private boolean browserSupportsAnimation() {
BrowserInfo bi = BrowserInfo.get();
- return !(bi.isIE6() || bi.isIE7() || bi.isSafari4());
+ return !(bi.isSafari4());
}
class VTreeTableScrollBody extends VScrollTable.VScrollTableBody {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java
new file mode 100644
index 0000000000..8c159f43de
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java
@@ -0,0 +1,101 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow;
+import com.vaadin.terminal.gwt.client.ui.VTreeTable.PendingNavigationEvent;
+
+public class VTreeTablePaintable extends VScrollTablePaintable {
+ public static final String ATTRIBUTE_HIERARCHY_COLUMN_INDEX = "hci";
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ FocusableScrollPanel widget = null;
+ int scrollPosition = 0;
+ if (getWidgetForPaintable().collapseRequest) {
+ widget = (FocusableScrollPanel) getWidgetForPaintable()
+ .getWidget(1);
+ scrollPosition = widget.getScrollPosition();
+ }
+ getWidgetForPaintable().animationsEnabled = uidl
+ .getBooleanAttribute("animate");
+ getWidgetForPaintable().colIndexOfHierarchy = uidl
+ .hasAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) ? uidl
+ .getIntAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) : 0;
+ int oldTotalRows = getWidgetForPaintable().getTotalRows();
+ super.updateFromUIDL(uidl, client);
+ if (getWidgetForPaintable().collapseRequest) {
+ if (getWidgetForPaintable().collapsedRowKey != null
+ && getWidgetForPaintable().scrollBody != null) {
+ VScrollTableRow row = getWidgetForPaintable()
+ .getRenderedRowByKey(
+ getWidgetForPaintable().collapsedRowKey);
+ if (row != null) {
+ getWidgetForPaintable().setRowFocus(row);
+ getWidgetForPaintable().focus();
+ }
+ }
+
+ int scrollPosition2 = widget.getScrollPosition();
+ if (scrollPosition != scrollPosition2) {
+ widget.setScrollPosition(scrollPosition);
+ }
+
+ // check which rows are needed from the server and initiate a
+ // deferred fetch
+ getWidgetForPaintable().onScroll(null);
+ }
+ // Recalculate table size if collapse request, or if page length is zero
+ // (not sent by server) and row count changes (#7908).
+ if (getWidgetForPaintable().collapseRequest
+ || (!uidl.hasAttribute("pagelength") && getWidgetForPaintable()
+ .getTotalRows() != oldTotalRows)) {
+ /*
+ * Ensure that possibly removed/added scrollbars are considered.
+ * Triggers row calculations, removes cached rows etc. Basically
+ * cleans up state. Be careful if touching this, you will break
+ * pageLength=0 if you remove this.
+ */
+ getWidgetForPaintable().triggerLazyColumnAdjustment(true);
+
+ getWidgetForPaintable().collapseRequest = false;
+ }
+ if (uidl.hasAttribute("focusedRow")) {
+ String key = uidl.getStringAttribute("focusedRow");
+ getWidgetForPaintable().setRowFocus(
+ getWidgetForPaintable().getRenderedRowByKey(key));
+ getWidgetForPaintable().focusParentResponsePending = false;
+ } else if (uidl.hasAttribute("clearFocusPending")) {
+ // Special case to detect a response to a focusParent request that
+ // does not return any focusedRow because the selected node has no
+ // parent
+ getWidgetForPaintable().focusParentResponsePending = false;
+ }
+
+ while (!getWidgetForPaintable().collapseRequest
+ && !getWidgetForPaintable().focusParentResponsePending
+ && !getWidgetForPaintable().pendingNavigationEvents.isEmpty()) {
+ // Keep replaying any queued events as long as we don't have any
+ // potential content changes pending
+ PendingNavigationEvent event = getWidgetForPaintable().pendingNavigationEvents
+ .removeFirst();
+ getWidgetForPaintable().handleNavigation(event.keycode, event.ctrl,
+ event.shift);
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VTreeTable.class);
+ }
+
+ @Override
+ public VTreeTable getWidgetForPaintable() {
+ return (VTreeTable) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java
index b569dbc94e..e733b2e73b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java
@@ -26,8 +26,7 @@ import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
@@ -157,18 +156,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler,
return selectionsCaption;
}
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // Captions are updated before super call to ensure the widths are set
- // correctly
- if (!uidl.getBooleanAttribute("cached")) {
- updateCaptions(uidl);
- }
-
- super.updateFromUIDL(uidl, client);
- }
-
- private void updateCaptions(UIDL uidl) {
+ protected void updateCaptions(UIDL uidl) {
String leftCaption = (uidl.hasAttribute(ATTRIBUTE_LEFT_CAPTION) ? uidl
.getStringAttribute(ATTRIBUTE_LEFT_CAPTION) : null);
String rightCaption = (uidl.hasAttribute(ATTRIBUTE_RIGHT_CAPTION) ? uidl
@@ -297,7 +285,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler,
Set<String> movedItems = moveSelectedItems(options, selections);
selectedKeys.addAll(movedItems);
- client.updateVariable(id, "selected",
+ client.updateVariable(paintableId, "selected",
selectedKeys.toArray(new String[selectedKeys.size()]),
isImmediate());
}
@@ -306,7 +294,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler,
Set<String> movedItems = moveSelectedItems(selections, options);
selectedKeys.removeAll(movedItems);
- client.updateVariable(id, "selected",
+ client.updateVariable(paintableId, "selected",
selectedKeys.toArray(new String[selectedKeys.size()]),
isImmediate());
}
@@ -385,16 +373,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler,
private void setInternalHeights() {
int captionHeight = 0;
- int totalHeight;
- if (BrowserInfo.get().isIE6()) {
- String o = getElement().getStyle().getOverflow();
-
- getElement().getStyle().setOverflow(Overflow.HIDDEN);
- totalHeight = getOffsetHeight();
- getElement().getStyle().setProperty("overflow", o);
- } else {
- totalHeight = getOffsetHeight();
- }
+ int totalHeight = getOffsetHeight();
if (optionsCaption != null) {
captionHeight = Util.getRequiredHeight(optionsCaption);
@@ -424,11 +403,6 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler,
int bordersAndPaddings = Util.measureHorizontalPaddingAndBorder(
buttons.getElement(), 0);
- if (BrowserInfo.get().isIE6()) {
- // IE6 sets a border on selects by default..
- bordersAndPaddings += 4;
- }
-
int buttonWidth = Util.getRequiredWidth(buttons);
int totalWidth = getOffsetWidth();
@@ -642,4 +616,8 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler,
return null;
}
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelectPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelectPaintable.java
new file mode 100644
index 0000000000..ce176113da
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelectPaintable.java
@@ -0,0 +1,34 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VTwinColSelectPaintable extends VOptionGroupBasePaintable {
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ // Captions are updated before super call to ensure the widths are set
+ // correctly
+ if (!uidl.getBooleanAttribute("cached")) {
+ getWidgetForPaintable().updateCaptions(uidl);
+ }
+
+ super.updateFromUIDL(uidl, client);
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VTwinColSelect.class);
+ }
+
+ @Override
+ public VTwinColSelect getWidgetForPaintable() {
+ return (VTwinColSelect) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java b/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java
index c7442e4436..ad702430f6 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java
@@ -6,18 +6,14 @@ package com.vaadin.terminal.gwt.client.ui;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.VerticalPanel;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.SimpleTree;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.VUIDLBrowser;
-public class VUnknownComponent extends Composite implements Paintable {
+public class VUnknownComponent extends Composite {
com.google.gwt.user.client.ui.Label caption = new com.google.gwt.user.client.ui.Label();;
SimpleTree uidlTree;
- private VerticalPanel panel;
- private String serverClassName = "unkwnown";
+ protected VerticalPanel panel;
+ protected String serverClassName = "unkwnown";
public VUnknownComponent() {
panel = new VerticalPanel();
@@ -31,28 +27,6 @@ public class VUnknownComponent extends Composite implements Paintable {
this.serverClassName = serverClassName;
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
- setCaption("Widgetset does not contain implementation for "
- + serverClassName
- + ". Check its @ClientWidget mapping, widgetsets "
- + "GWT module description file and re-compile your"
- + " widgetset. In case you have downloaded a vaadin"
- + " add-on package, you might want to refer to "
- + "<a href='http://vaadin.com/using-addons'>add-on "
- + "instructions</a>. Unrendered UIDL:");
- if (uidlTree != null) {
- uidlTree.removeFromParent();
- }
-
- uidlTree = new VUIDLBrowser(uidl, client.getConfiguration());
- uidlTree.open(true);
- uidlTree.setText("Unrendered UIDL");
- panel.add(uidlTree);
- }
-
public void setCaption(String c) {
caption.getElement().setInnerHTML(c);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponentPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponentPaintable.java
new file mode 100644
index 0000000000..252d7528ca
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponentPaintable.java
@@ -0,0 +1,52 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VUIDLBrowser;
+
+public class VUnknownComponentPaintable extends VAbstractPaintableWidget {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+ getWidgetForPaintable().setCaption(
+ "Widgetset does not contain implementation for "
+ + getWidgetForPaintable().serverClassName
+ + ". Check its @ClientWidget mapping, widgetsets "
+ + "GWT module description file and re-compile your"
+ + " widgetset. In case you have downloaded a vaadin"
+ + " add-on package, you might want to refer to "
+ + "<a href='http://vaadin.com/using-addons'>add-on "
+ + "instructions</a>. Unrendered UIDL:");
+ if (getWidgetForPaintable().uidlTree != null) {
+ getWidgetForPaintable().uidlTree.removeFromParent();
+ }
+
+ getWidgetForPaintable().uidlTree = new VUIDLBrowser(uidl,
+ client.getConfiguration());
+ getWidgetForPaintable().uidlTree.open(true);
+ getWidgetForPaintable().uidlTree.setText("Unrendered UIDL");
+ getWidgetForPaintable().panel.add(getWidgetForPaintable().uidlTree);
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VUnknownComponent.class);
+ }
+
+ @Override
+ public VUnknownComponent getWidgetForPaintable() {
+ return (VUnknownComponent) super.getWidgetForPaintable();
+ }
+
+ public void setServerSideClassName(String serverClassName) {
+ getWidgetForPaintable().setServerSideClassName(serverClassName);
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUpload.java b/src/com/vaadin/terminal/gwt/client/ui/VUpload.java
index f3105b70a1..bc94ae317a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VUpload.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VUpload.java
@@ -23,8 +23,6 @@ import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.VTooltip;
@@ -34,7 +32,7 @@ import com.vaadin.terminal.gwt.client.VTooltip;
* events even though the upload component is already detached.
*
*/
-public class VUpload extends SimplePanel implements Paintable {
+public class VUpload extends SimplePanel {
private final class MyFileUpload extends FileUpload {
@Override
@@ -72,19 +70,19 @@ public class VUpload extends SimplePanel implements Paintable {
ApplicationConnection client;
- private String paintableId;
+ protected String paintableId;
/**
* Button that initiates uploading
*/
- private final VButton submitButton;
+ protected final VButton submitButton;
/**
* When expecting big files, programmer may initiate some UI changes when
* uploading the file starts. Bit after submitting file we'll visit the
* server to check possible changes.
*/
- private Timer t;
+ protected Timer t;
/**
* some browsers tries to send form twice if submit is called in button
@@ -99,11 +97,11 @@ public class VUpload extends SimplePanel implements Paintable {
private Hidden maxfilesize = new Hidden();
- private FormElement element;
+ protected FormElement element;
private com.google.gwt.dom.client.Element synthesizedFrame;
- private int nextUploadId;
+ protected int nextUploadId;
public VUpload() {
super(com.google.gwt.dom.client.Document.get().createFormElement());
@@ -136,7 +134,7 @@ public class VUpload extends SimplePanel implements Paintable {
@Override
public void onBrowserEvent(Event event) {
if ((event.getTypeInt() & VTooltip.TOOLTIP_EVENTS) > 0) {
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
super.onBrowserEvent(event);
}
@@ -144,47 +142,9 @@ public class VUpload extends SimplePanel implements Paintable {
private static native void setEncoding(Element form, String encoding)
/*-{
form.enctype = encoding;
- // For IE6
- form.encoding = encoding;
}-*/;
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
- if (uidl.hasAttribute("notStarted")) {
- t.schedule(400);
- return;
- }
- if (uidl.hasAttribute("forceSubmit")) {
- submit();
- return;
- }
- setImmediate(uidl.getBooleanAttribute("immediate"));
- this.client = client;
- paintableId = uidl.getId();
- nextUploadId = uidl.getIntAttribute("nextid");
- final String action = client.translateVaadinUri(uidl
- .getStringVariable("action"));
- element.setAction(action);
- if (uidl.hasAttribute("buttoncaption")) {
- submitButton.setText(uidl.getStringAttribute("buttoncaption"));
- submitButton.setVisible(true);
- } else {
- submitButton.setVisible(false);
- }
- fu.setName(paintableId + "_file");
-
- if (uidl.hasAttribute("disabled") || uidl.hasAttribute("readonly")) {
- disableUpload();
- } else if (!uidl.getBooleanAttribute("state")) {
- // Enable the button only if an upload is not in progress
- enableUpload();
- ensureTargetFrame();
- }
- }
-
- private void setImmediate(boolean booleanAttribute) {
+ protected void setImmediate(boolean booleanAttribute) {
if (immediate != booleanAttribute) {
immediate = booleanAttribute;
if (immediate) {
@@ -278,7 +238,7 @@ public class VUpload extends SimplePanel implements Paintable {
});
}
- private void submit() {
+ protected void submit() {
if (fu.getFilename().length() == 0 || submitted || !enabled) {
VConsole.log("Submit cancelled (disabled, no file or already submitted)");
return;
@@ -316,15 +276,12 @@ public class VUpload extends SimplePanel implements Paintable {
}
}
- private void ensureTargetFrame() {
+ protected void ensureTargetFrame() {
if (synthesizedFrame == null) {
// Attach a hidden IFrame to the form. This is the target iframe to
- // which
- // the form will be submitted. We have to create the iframe using
- // innerHTML,
- // because setting an iframe's 'name' property dynamically doesn't
- // work on
- // most browsers.
+ // which the form will be submitted. We have to create the iframe
+ // using innerHTML, because setting an iframe's 'name' property
+ // dynamically doesn't work on most browsers.
DivElement dummy = Document.get().createDivElement();
dummy.setInnerHTML("<iframe src=\"javascript:''\" name='"
+ getFrameName()
@@ -355,5 +312,4 @@ public class VUpload extends SimplePanel implements Paintable {
synthesizedFrame = null;
}
}
-
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUploadPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VUploadPaintable.java
new file mode 100644
index 0000000000..7fd59fc176
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VUploadPaintable.java
@@ -0,0 +1,62 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VUploadPaintable extends VAbstractPaintableWidget {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+ if (uidl.hasAttribute("notStarted")) {
+ getWidgetForPaintable().t.schedule(400);
+ return;
+ }
+ if (uidl.hasAttribute("forceSubmit")) {
+ getWidgetForPaintable().submit();
+ return;
+ }
+ getWidgetForPaintable().setImmediate(
+ uidl.getBooleanAttribute("immediate"));
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().paintableId = uidl.getId();
+ getWidgetForPaintable().nextUploadId = uidl.getIntAttribute("nextid");
+ final String action = client.translateVaadinUri(uidl
+ .getStringVariable("action"));
+ getWidgetForPaintable().element.setAction(action);
+ if (uidl.hasAttribute("buttoncaption")) {
+ getWidgetForPaintable().submitButton.setText(uidl
+ .getStringAttribute("buttoncaption"));
+ getWidgetForPaintable().submitButton.setVisible(true);
+ } else {
+ getWidgetForPaintable().submitButton.setVisible(false);
+ }
+ getWidgetForPaintable().fu.setName(getWidgetForPaintable().paintableId
+ + "_file");
+
+ if (uidl.hasAttribute("disabled") || uidl.hasAttribute("readonly")) {
+ getWidgetForPaintable().disableUpload();
+ } else if (!uidl.getBooleanAttribute("state")) {
+ // Enable the button only if an upload is not in progress
+ getWidgetForPaintable().enableUpload();
+ getWidgetForPaintable().ensureTargetFrame();
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VUpload.class);
+ }
+
+ @Override
+ public VUpload getWidgetForPaintable() {
+ return (VUpload) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java b/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java
deleted file mode 100644
index db01699383..0000000000
--- a/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.History;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-/**
- * Client side implementation for UriFragmentUtility. Uses GWT's History object
- * as an implementation.
- *
- */
-public class VUriFragmentUtility extends Widget implements Paintable,
- ValueChangeHandler<String> {
-
- private String fragment;
- private ApplicationConnection client;
- private String paintableId;
- private boolean immediate;
- private HandlerRegistration historyValueHandlerRegistration;
-
- public VUriFragmentUtility() {
- setElement(Document.get().createDivElement());
- if (BrowserInfo.get().isIE6()) {
- getElement().getStyle().setProperty("overflow", "hidden");
- getElement().getStyle().setProperty("height", "0");
- }
- }
-
- @Override
- protected void onAttach() {
- super.onAttach();
- historyValueHandlerRegistration = History.addValueChangeHandler(this);
- History.fireCurrentHistoryState();
- }
-
- @Override
- protected void onDetach() {
- super.onDetach();
- historyValueHandlerRegistration.removeHandler();
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
- String uidlFragment = uidl.getStringVariable("fragment");
- immediate = uidl.getBooleanAttribute("immediate");
- if (this.client == null) {
- // initial paint has some special logic
- this.client = client;
- paintableId = uidl.getId();
- if (!fragment.equals(uidlFragment)) {
- // initial server side fragment (from link/bookmark/typed) does
- // not equal the one on
- // server, send initial fragment to server
- History.fireCurrentHistoryState();
- }
- } else {
- if (uidlFragment != null && !uidlFragment.equals(fragment)) {
- fragment = uidlFragment;
- // normal fragment change from server, add new history item
- History.newItem(uidlFragment, false);
- }
- }
- }
-
- public void onValueChange(ValueChangeEvent<String> event) {
- String historyToken = event.getValue();
- fragment = historyToken;
- if (client != null) {
- client.updateVariable(paintableId, "fragment", fragment, immediate);
- }
- }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayoutPaintable.java
new file mode 100644
index 0000000000..b911d0f013
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayoutPaintable.java
@@ -0,0 +1,17 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+
+public class VVerticalLayoutPaintable extends VOrderedLayoutPaintable {
+
+ @Override
+ public VVerticalLayout getWidgetForPaintable() {
+ return (VVerticalLayout) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected VVerticalLayout createWidget() {
+ return GWT.create(VVerticalLayout.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVerticalSplitPanelPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VVerticalSplitPanelPaintable.java
new file mode 100644
index 0000000000..5b8f978b28
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VVerticalSplitPanelPaintable.java
@@ -0,0 +1,12 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+
+public class VVerticalSplitPanelPaintable extends VAbstractSplitPanelPaintable {
+
+ @Override
+ protected VAbstractSplitPanel createWidget() {
+ return GWT.create(VSplitPanelVertical.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVideo.java b/src/com/vaadin/terminal/gwt/client/ui/VVideo.java
index 92b93ac96b..36f17e1436 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VVideo.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VVideo.java
@@ -8,12 +8,9 @@ import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.VideoElement;
import com.google.gwt.user.client.Element;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
public class VVideo extends VMediaBase {
- public static final String ATTR_POSTER = "poster";
private static String CLASSNAME = "v-video";
@@ -27,22 +24,6 @@ public class VVideo extends VMediaBase {
updateDimensionsWhenMetadataLoaded(getElement());
}
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
- super.updateFromUIDL(uidl, client);
- setPosterFromUIDL(uidl);
- }
-
- private void setPosterFromUIDL(UIDL uidl) {
- if (uidl.hasAttribute(ATTR_POSTER)) {
- video.setPoster(client.translateVaadinUri(uidl
- .getStringAttribute(ATTR_POSTER)));
- }
- }
-
/**
* Registers a listener that updates the dimensions of the widget when the
* video metadata has been loaded.
@@ -74,4 +55,9 @@ public class VVideo extends VMediaBase {
protected String getDefaultAltHtml() {
return "Your browser does not support the <code>video</code> element.";
}
+
+ public void setPoster(String poster) {
+ video.setPoster(poster);
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVideoPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VVideoPaintable.java
new file mode 100644
index 0000000000..ac4b735cae
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VVideoPaintable.java
@@ -0,0 +1,38 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VVideoPaintable extends VMediaBasePaintable {
+ public static final String ATTR_POSTER = "poster";
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+ super.updateFromUIDL(uidl, client);
+ setPosterFromUIDL(uidl);
+ }
+
+ private void setPosterFromUIDL(UIDL uidl) {
+ if (uidl.hasAttribute(ATTR_POSTER)) {
+ getWidgetForPaintable().setPoster(
+ getConnection().translateVaadinUri(
+ uidl.getStringAttribute(ATTR_POSTER)));
+ }
+ }
+
+ @Override
+ public VVideo getWidgetForPaintable() {
+ return (VVideo) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VVideo.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java
index 07ade6a8b1..7002c6279f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VView.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VView.java
@@ -5,8 +5,6 @@
package com.vaadin.terminal.gwt.client.ui;
import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -17,28 +15,28 @@ import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.event.dom.client.DomEvent.Type;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
-import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
/**
@@ -47,19 +45,21 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHan
public class VView extends SimplePanel implements Container, ResizeHandler,
Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable {
+ public static final String FRAGMENT_VARIABLE = "fragment";
+
private static final String CLASSNAME = "v-view";
public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain";
- private String theme;
+ String theme;
- private Paintable layout;
+ VPaintableWidget layout;
- private final LinkedHashSet<VWindow> subWindows = new LinkedHashSet<VWindow>();
+ final LinkedHashSet<VWindow> subWindows = new LinkedHashSet<VWindow>();
- private String id;
+ String id;
- private ShortcutActionHandler actionHandler;
+ ShortcutActionHandler actionHandler;
/** stored width for IE resize optimization */
private int width;
@@ -67,7 +67,10 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
/** stored height for IE resize optimization */
private int height;
- private ApplicationConnection connection;
+ ApplicationConnection connection;
+
+ /** Identifies the click event */
+ public static final String CLICK_EVENT_ID = "click";
/**
* We are postponing resize process with IE. IE bugs with scrollbars in some
@@ -77,32 +80,51 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
*/
private Timer resizeTimer;
- private int scrollTop;
+ int scrollTop;
- private int scrollLeft;
+ int scrollLeft;
- private boolean rendering;
+ boolean rendering;
- private boolean scrollable;
+ boolean scrollable;
- private boolean immediate;
+ boolean immediate;
- private boolean resizeLazy = false;
+ boolean resizeLazy = false;
+ /**
+ * Attribute name for the lazy resize setting .
+ */
public static final String RESIZE_LAZY = "rL";
+
/**
* Reference to the parent frame/iframe. Null if there is no parent (i)frame
* or if the application and parent frame are in different domains.
*/
- private Element parentFrame;
+ Element parentFrame;
- private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
- VPanel.CLICK_EVENT_IDENTIFIER) {
+ private HandlerRegistration historyHandlerRegistration;
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
+ /**
+ * The current URI fragment, used to avoid sending updates if nothing has
+ * changed.
+ */
+ String currentFragment;
+
+ /**
+ * Listener for URI fragment changes. Notifies the server of the new value
+ * whenever the value changes.
+ */
+ private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() {
+ public void onValueChange(ValueChangeEvent<String> event) {
+ String newFragment = event.getValue();
+
+ // Send the new fragment to the server if it has changed
+ if (!newFragment.equals(currentFragment) && connection != null) {
+ currentFragment = newFragment;
+ connection.updateVariable(id, FRAGMENT_VARIABLE, newFragment,
+ true);
+ }
}
};
@@ -124,6 +146,21 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
getElement().setTabIndex(-1);
}
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ historyHandlerRegistration = History
+ .addValueChangeHandler(historyChangeHandler);
+ currentFragment = History.getToken();
+ }
+
+ @Override
+ protected void onDetach() {
+ super.onDetach();
+ historyHandlerRegistration.removeHandler();
+ historyHandlerRegistration = null;
+ }
+
/**
* Called when the window might have been resized.
*
@@ -160,7 +197,7 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
/**
* Used to reload host page on theme changes.
*/
- private static native void reloadHostPage()
+ static native void reloadHostPage()
/*-{
$wnd.location.reload();
}-*/;
@@ -171,7 +208,7 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
* @param script
* Script to be executed.
*/
- private static native void eval(String script)
+ static native void eval(String script)
/*-{
try {
if (script == null) return;
@@ -192,217 +229,6 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
.contains(ApplicationConnection.GENERATED_BODY_CLASSNAME);
}
- public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
- rendering = true;
-
- id = uidl.getId();
- boolean firstPaint = connection == null;
- connection = client;
-
- immediate = uidl.hasAttribute("immediate");
- resizeLazy = uidl.hasAttribute(RESIZE_LAZY);
- String newTheme = uidl.getStringAttribute("theme");
- if (theme != null && !newTheme.equals(theme)) {
- // Complete page refresh is needed due css can affect layout
- // calculations etc
- reloadHostPage();
- } else {
- theme = newTheme;
- }
- if (uidl.hasAttribute("style")) {
- setStyleName(getStylePrimaryName() + " "
- + uidl.getStringAttribute("style"));
- }
-
- if (uidl.hasAttribute("name")) {
- client.setWindowName(uidl.getStringAttribute("name"));
- }
-
- clickEventHandler.handleEventHandlerRegistration(client);
-
- if (!isEmbedded()) {
- // only change window title if we're in charge of the whole page
- com.google.gwt.user.client.Window.setTitle(uidl
- .getStringAttribute("caption"));
- }
-
- // Process children
- int childIndex = 0;
-
- // Open URL:s
- boolean isClosed = false; // was this window closed?
- while (childIndex < uidl.getChildCount()
- && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
- final UIDL open = uidl.getChildUIDL(childIndex);
- final String url = client.translateVaadinUri(open
- .getStringAttribute("src"));
- final String target = open.getStringAttribute("name");
- if (target == null) {
- // source will be opened to this browser window, but we may have
- // to finish rendering this window in case this is a download
- // (and window stays open).
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- goTo(url);
- }
- });
- } else if ("_self".equals(target)) {
- // This window is closing (for sure). Only other opens are
- // relevant in this change. See #3558, #2144
- isClosed = true;
- goTo(url);
- } else {
- String options;
- if (open.hasAttribute("border")) {
- if (open.getStringAttribute("border").equals("minimal")) {
- options = "menubar=yes,location=no,status=no";
- } else {
- options = "menubar=no,location=no,status=no";
- }
-
- } else {
- options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
- }
-
- if (open.hasAttribute("width")) {
- int w = open.getIntAttribute("width");
- options += ",width=" + w;
- }
- if (open.hasAttribute("height")) {
- int h = open.getIntAttribute("height");
- options += ",height=" + h;
- }
-
- Window.open(url, target, options);
- }
- childIndex++;
- }
- if (isClosed) {
- // don't render the content, something else will be opened to this
- // browser view
- rendering = false;
- return;
- }
-
- // Draw this application level window
- UIDL childUidl = uidl.getChildUIDL(childIndex);
- final Paintable lo = client.getPaintable(childUidl);
-
- if (layout != null) {
- if (layout != lo) {
- // remove old
- client.unregisterPaintable(layout);
- // add new
- setWidget((Widget) lo);
- layout = lo;
- }
- } else {
- setWidget((Widget) lo);
- layout = lo;
- }
-
- layout.updateFromUIDL(childUidl, client);
- if (!childUidl.getBooleanAttribute("cached")) {
- updateParentFrameSize();
- }
-
- // Save currently open subwindows to track which will need to be closed
- final HashSet<VWindow> removedSubWindows = new HashSet<VWindow>(
- subWindows);
-
- // Handle other UIDL children
- while ((childUidl = uidl.getChildUIDL(++childIndex)) != null) {
- String tag = childUidl.getTag().intern();
- if (tag == "actions") {
- if (actionHandler == null) {
- actionHandler = new ShortcutActionHandler(id, client);
- }
- actionHandler.updateActionMap(childUidl);
- } else if (tag == "execJS") {
- String script = childUidl.getStringAttribute("script");
- eval(script);
- } else if (tag == "notifications") {
- for (final Iterator<?> it = childUidl.getChildIterator(); it
- .hasNext();) {
- final UIDL notification = (UIDL) it.next();
- VNotification.showNotification(client, notification);
- }
- } else {
- // subwindows
- final Paintable w = client.getPaintable(childUidl);
- if (subWindows.contains(w)) {
- removedSubWindows.remove(w);
- } else {
- subWindows.add((VWindow) w);
- }
- w.updateFromUIDL(childUidl, client);
- }
- }
-
- // Close old windows which where not in UIDL anymore
- for (final Iterator<VWindow> rem = removedSubWindows.iterator(); rem
- .hasNext();) {
- final VWindow w = rem.next();
- client.unregisterPaintable(w);
- subWindows.remove(w);
- w.hide();
- }
-
- if (uidl.hasAttribute("focused")) {
- // set focused component when render phase is finished
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- final Paintable toBeFocused = uidl.getPaintableAttribute(
- "focused", connection);
-
- /*
- * Two types of Widgets can be focused, either implementing
- * GWT HasFocus of a thinner Vaadin specific Focusable
- * interface.
- */
- if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
- final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
- toBeFocusedWidget.setFocus(true);
- } else if (toBeFocused instanceof Focusable) {
- ((Focusable) toBeFocused).focus();
- } else {
- VConsole.log("Could not focus component");
- }
- }
- });
- }
-
- // Add window listeners on first paint, to prevent premature
- // variablechanges
- if (firstPaint) {
- Window.addWindowClosingHandler(this);
- Window.addResizeHandler(this);
- }
-
- onResize();
-
- // finally set scroll position from UIDL
- if (uidl.hasVariable("scrollTop")) {
- scrollable = true;
- scrollTop = uidl.getIntVariable("scrollTop");
- DOM.setElementPropertyInt(getElement(), "scrollTop", scrollTop);
- scrollLeft = uidl.getIntVariable("scrollLeft");
- DOM.setElementPropertyInt(getElement(), "scrollLeft", scrollLeft);
- } else {
- scrollable = false;
- }
-
- // Safari workaround must be run after scrollTop is updated as it sets
- // scrollTop using a deferred command.
- if (BrowserInfo.get().isSafari()) {
- Util.runWebkitOverflowAutoFix(getElement());
- }
-
- scrollIntoView(uidl);
-
- rendering = false;
- }
-
/**
* Tries to scroll paintable referenced from given UIDL snippet to be
* visible.
@@ -413,9 +239,10 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
if (uidl.hasAttribute("scrollTo")) {
Scheduler.get().scheduleDeferred(new Command() {
public void execute() {
- final Paintable paintable = uidl.getPaintableAttribute(
- "scrollTo", connection);
- ((Widget) paintable).getElement().scrollIntoView();
+ final VPaintableWidget paintable = (VPaintableWidget) uidl
+ .getPaintableAttribute("scrollTo", connection);
+ paintable.getWidgetForPaintable().getElement()
+ .scrollIntoView();
}
});
}
@@ -465,7 +292,7 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
/**
* Called when a resize event is received.
*/
- private void onResize() {
+ void onResize() {
/*
* IE (pre IE9 at least) will give us some false resize events due to
* problems with scrollbars. Firefox 3 might also produce some extra
@@ -476,9 +303,7 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
* browser window. Constantly recalculating the layout causes the resize
* operation to be really slow with complex layouts.
*/
- boolean lazy = resizeLazy
- || (BrowserInfo.get().isIE() && BrowserInfo.get()
- .getIEVersion() <= 8) || BrowserInfo.get().isFF3();
+ boolean lazy = resizeLazy || BrowserInfo.get().isIE8();
if (lazy) {
delayedResizeExecutor.trigger();
@@ -509,10 +334,6 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
// also related BeforeShortcutActionListener interface. Same interface
// might be usable here.
VTextField.flushChangesFromFocusedTextField();
-
- // Send the closing state to server
- connection.updateVariable(id, "close", true, false);
- connection.sendPendingVariableChangesSync();
}
private final RenderSpace myRenderSpace = new RenderSpace() {
@@ -563,16 +384,6 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
@Override
public int getWidth() {
- int w = getRealWidth();
- if (w < 10 && BrowserInfo.get().isIE7()) {
- // Overcome an IE7 bug #3295
- Util.shakeBodyElement();
- w = getRealWidth();
- }
- return w;
- }
-
- private int getRealWidth() {
if (connection.getConfiguration().isStandalone()) {
return getElement().getOffsetWidth() - getExcessWidth();
}
@@ -602,7 +413,7 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
Element targetElement;
if (appId.equals(ownAppId)) {
// Only hide the contents of current application
- targetElement = ((Widget) layout).getElement();
+ targetElement = layout.getWidgetForPaintable().getElement();
} else {
// Hide everything for other applications
targetElement = Document.get().getElementById(appId);
@@ -620,7 +431,7 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
String appId = vaadinApps.get(i);
Element targetElement;
if (appId.equals(ownAppId)) {
- targetElement = ((Widget) layout).getElement();
+ targetElement = layout.getWidgetForPaintable().getElement();
} else {
targetElement = Document.get().getElementById(appId);
}
@@ -676,10 +487,10 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
}
setWidget(newComponent);
- layout = (Paintable) newComponent;
+ layout = (VPaintableWidget) newComponent;
}
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
/*
* Can never propagate further and we do not want need to re-layout the
* layout which has caused this request.
@@ -687,13 +498,13 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
updateParentFrameSize();
// layout size change may affect its available space (scrollbars)
- connection.handleComponentRelativeSize((Widget) layout);
+ connection.handleComponentRelativeSize(layout.getWidgetForPaintable());
return true;
}
- private void updateParentFrameSize() {
+ void updateParentFrameSize() {
if (parentFrame == null) {
return;
}
@@ -705,7 +516,7 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
parentFrame.getStyle().setPropertyPx("height", childHeight);
}
- private static native Element getParentFrame()
+ static native Element getParentFrame()
/*-{
try {
var frameElement = $wnd.frameElement;
@@ -720,10 +531,6 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
return null;
}-*/;
- public void updateCaption(Paintable component, UIDL uidl) {
- // NOP Subwindows never draw caption for their first child (layout)
- }
-
/**
* Return an iterator for current subwindows. This method is meant for
* testing purposes only.
@@ -738,36 +545,6 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
return windows;
}
- public void init(String rootPanelId,
- ApplicationConnection applicationConnection) {
- DOM.sinkEvents(getElement(), Event.ONKEYDOWN | Event.ONSCROLL);
-
- // iview is focused when created so element needs tabIndex
- // 1 due 0 is at the end of natural tabbing order
- DOM.setElementProperty(getElement(), "tabIndex", "1");
-
- RootPanel root = RootPanel.get(rootPanelId);
-
- // Remove the v-app-loading or any splash screen added inside the div by
- // the user
- root.getElement().setInnerHTML("");
- // For backwards compatibility with static index pages only.
- // No longer added by AbstractApplicationServlet/Portlet
- root.removeStyleName("v-app-loading");
-
- root.add(this);
-
- if (applicationConnection.getConfiguration().isStandalone()) {
- // set focus to iview element by default to listen possible keyboard
- // shortcuts. For embedded applications this is unacceptable as we
- // don't want to steal focus from the main page nor we don't want
- // side-effects from focusing (scrollIntoView).
- getElement().focus();
- }
-
- parentFrame = getParentFrame();
- }
-
public ShortcutActionHandler getShortcutActionHandler() {
return actionHandler;
}
@@ -776,4 +553,8 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
getElement().focus();
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VViewPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VViewPaintable.java
new file mode 100644
index 0000000000..ccf7185c14
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VViewPaintable.java
@@ -0,0 +1,331 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Focusable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public class VViewPaintable extends VAbstractPaintableWidgetContainer {
+
+ private static final String CLICK_EVENT_IDENTIFIER = VPanelPaintable.CLICK_EVENT_IDENTIFIER;
+
+ public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().rendering = true;
+
+ getWidgetForPaintable().id = uidl.getId();
+ boolean firstPaint = getWidgetForPaintable().connection == null;
+ getWidgetForPaintable().connection = client;
+
+ getWidgetForPaintable().immediate = uidl.hasAttribute("immediate");
+ getWidgetForPaintable().resizeLazy = uidl
+ .hasAttribute(VView.RESIZE_LAZY);
+ String newTheme = uidl.getStringAttribute("theme");
+ if (getWidgetForPaintable().theme != null
+ && !newTheme.equals(getWidgetForPaintable().theme)) {
+ // Complete page refresh is needed due css can affect layout
+ // calculations etc
+ getWidgetForPaintable().reloadHostPage();
+ } else {
+ getWidgetForPaintable().theme = newTheme;
+ }
+ if (uidl.hasAttribute("style")) {
+ getWidgetForPaintable().setStyleName(
+ getWidgetForPaintable().getStylePrimaryName() + " "
+ + uidl.getStringAttribute("style"));
+ }
+
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ if (!getWidgetForPaintable().isEmbedded()
+ && uidl.hasAttribute("caption")) {
+ // only change window title if we're in charge of the whole page
+ com.google.gwt.user.client.Window.setTitle(uidl
+ .getStringAttribute("caption"));
+ }
+
+ // Process children
+ int childIndex = 0;
+
+ // Open URL:s
+ boolean isClosed = false; // was this window closed?
+ while (childIndex < uidl.getChildCount()
+ && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
+ final UIDL open = uidl.getChildUIDL(childIndex);
+ final String url = client.translateVaadinUri(open
+ .getStringAttribute("src"));
+ final String target = open.getStringAttribute("name");
+ if (target == null) {
+ // source will be opened to this browser window, but we may have
+ // to finish rendering this window in case this is a download
+ // (and window stays open).
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ VView.goTo(url);
+ }
+ });
+ } else if ("_self".equals(target)) {
+ // This window is closing (for sure). Only other opens are
+ // relevant in this change. See #3558, #2144
+ isClosed = true;
+ VView.goTo(url);
+ } else {
+ String options;
+ if (open.hasAttribute("border")) {
+ if (open.getStringAttribute("border").equals("minimal")) {
+ options = "menubar=yes,location=no,status=no";
+ } else {
+ options = "menubar=no,location=no,status=no";
+ }
+
+ } else {
+ options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
+ }
+
+ if (open.hasAttribute("width")) {
+ int w = open.getIntAttribute("width");
+ options += ",width=" + w;
+ }
+ if (open.hasAttribute("height")) {
+ int h = open.getIntAttribute("height");
+ options += ",height=" + h;
+ }
+
+ Window.open(url, target, options);
+ }
+ childIndex++;
+ }
+ if (isClosed) {
+ // don't render the content, something else will be opened to this
+ // browser view
+ getWidgetForPaintable().rendering = false;
+ return;
+ }
+
+ // Draw this application level window
+ UIDL childUidl = uidl.getChildUIDL(childIndex);
+ final VPaintableWidget lo = client.getPaintable(childUidl);
+
+ if (getWidgetForPaintable().layout != null) {
+ if (getWidgetForPaintable().layout != lo) {
+ // remove old
+ client.unregisterPaintable(getWidgetForPaintable().layout);
+ // add new
+ getWidgetForPaintable().setWidget(lo.getWidgetForPaintable());
+ getWidgetForPaintable().layout = lo;
+ }
+ } else {
+ getWidgetForPaintable().setWidget(lo.getWidgetForPaintable());
+ getWidgetForPaintable().layout = lo;
+ }
+
+ getWidgetForPaintable().layout.updateFromUIDL(childUidl, client);
+ if (!childUidl.getBooleanAttribute("cached")) {
+ getWidgetForPaintable().updateParentFrameSize();
+ }
+
+ // Save currently open subwindows to track which will need to be closed
+ final HashSet<VWindow> removedSubWindows = new HashSet<VWindow>(
+ getWidgetForPaintable().subWindows);
+
+ // Handle other UIDL children
+ while ((childUidl = uidl.getChildUIDL(++childIndex)) != null) {
+ String tag = childUidl.getTag().intern();
+ if (tag == "actions") {
+ if (getWidgetForPaintable().actionHandler == null) {
+ getWidgetForPaintable().actionHandler = new ShortcutActionHandler(
+ getWidgetForPaintable().id, client);
+ }
+ getWidgetForPaintable().actionHandler
+ .updateActionMap(childUidl);
+ } else if (tag == "execJS") {
+ String script = childUidl.getStringAttribute("script");
+ VView.eval(script);
+ } else if (tag == "notifications") {
+ for (final Iterator<?> it = childUidl.getChildIterator(); it
+ .hasNext();) {
+ final UIDL notification = (UIDL) it.next();
+ VNotification.showNotification(client, notification);
+ }
+ } else {
+ // subwindows
+ final VPaintableWidget w = client.getPaintable(childUidl);
+ if (getWidgetForPaintable().subWindows.contains(w)) {
+ removedSubWindows.remove(w);
+ } else {
+ getWidgetForPaintable().subWindows.add((VWindow) w);
+ }
+ w.updateFromUIDL(childUidl, client);
+ }
+ }
+
+ // Close old windows which where not in UIDL anymore
+ for (final Iterator<VWindow> rem = removedSubWindows.iterator(); rem
+ .hasNext();) {
+ final VWindow w = rem.next();
+ client.unregisterPaintable(VPaintableMap.get(getConnection())
+ .getPaintable(w));
+ getWidgetForPaintable().subWindows.remove(w);
+ w.hide();
+ }
+
+ if (uidl.hasAttribute("focused")) {
+ // set focused component when render phase is finished
+ Scheduler.get().scheduleDeferred(new Command() {
+ public void execute() {
+ VPaintableWidget paintable = (VPaintableWidget) uidl
+ .getPaintableAttribute("focused", getConnection());
+
+ final Widget toBeFocused = paintable
+ .getWidgetForPaintable();
+ /*
+ * Two types of Widgets can be focused, either implementing
+ * GWT HasFocus of a thinner Vaadin specific Focusable
+ * interface.
+ */
+ if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
+ final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
+ toBeFocusedWidget.setFocus(true);
+ } else if (toBeFocused instanceof Focusable) {
+ ((Focusable) toBeFocused).focus();
+ } else {
+ VConsole.log("Could not focus component");
+ }
+ }
+ });
+ }
+
+ // Add window listeners on first paint, to prevent premature
+ // variablechanges
+ if (firstPaint) {
+ Window.addWindowClosingHandler(getWidgetForPaintable());
+ Window.addResizeHandler(getWidgetForPaintable());
+ }
+
+ getWidgetForPaintable().onResize();
+
+ // finally set scroll position from UIDL
+ if (uidl.hasVariable("scrollTop")) {
+ getWidgetForPaintable().scrollable = true;
+ getWidgetForPaintable().scrollTop = uidl
+ .getIntVariable("scrollTop");
+ DOM.setElementPropertyInt(getWidgetForPaintable().getElement(),
+ "scrollTop", getWidgetForPaintable().scrollTop);
+ getWidgetForPaintable().scrollLeft = uidl
+ .getIntVariable("scrollLeft");
+ DOM.setElementPropertyInt(getWidgetForPaintable().getElement(),
+ "scrollLeft", getWidgetForPaintable().scrollLeft);
+ } else {
+ getWidgetForPaintable().scrollable = false;
+ }
+
+ // Safari workaround must be run after scrollTop is updated as it sets
+ // scrollTop using a deferred command.
+ if (BrowserInfo.get().isSafari()) {
+ Util.runWebkitOverflowAutoFix(getWidgetForPaintable().getElement());
+ }
+
+ getWidgetForPaintable().scrollIntoView(uidl);
+
+ if (uidl.hasAttribute(VView.FRAGMENT_VARIABLE)) {
+ getWidgetForPaintable().currentFragment = uidl
+ .getStringAttribute(VView.FRAGMENT_VARIABLE);
+ if (!getWidgetForPaintable().currentFragment.equals(History
+ .getToken())) {
+ History.newItem(getWidgetForPaintable().currentFragment, true);
+ }
+ } else {
+ // Initial request for which the server doesn't yet have a fragment
+ // (and haven't shown any interest in getting one)
+ getWidgetForPaintable().currentFragment = History.getToken();
+
+ // Include current fragment in the next request
+ client.updateVariable(getWidgetForPaintable().id,
+ VView.FRAGMENT_VARIABLE,
+ getWidgetForPaintable().currentFragment, false);
+ }
+
+ getWidgetForPaintable().rendering = false;
+ }
+
+ public void init(String rootPanelId,
+ ApplicationConnection applicationConnection) {
+ DOM.sinkEvents(getWidgetForPaintable().getElement(), Event.ONKEYDOWN
+ | Event.ONSCROLL);
+
+ // iview is focused when created so element needs tabIndex
+ // 1 due 0 is at the end of natural tabbing order
+ DOM.setElementProperty(getWidgetForPaintable().getElement(),
+ "tabIndex", "1");
+
+ RootPanel root = RootPanel.get(rootPanelId);
+
+ // Remove the v-app-loading or any splash screen added inside the div by
+ // the user
+ root.getElement().setInnerHTML("");
+ // For backwards compatibility with static index pages only.
+ // No longer added by AbstractApplicationServlet/Portlet
+ root.removeStyleName("v-app-loading");
+
+ String themeUri = applicationConnection.getConfiguration()
+ .getThemeUri();
+ String themeName = themeUri.substring(themeUri.lastIndexOf('/'));
+ themeName = themeName.replaceAll("[^a-zA-Z0-9]", "");
+ root.addStyleName("v-theme-" + themeName);
+
+ root.add(getWidgetForPaintable());
+
+ if (applicationConnection.getConfiguration().isStandalone()) {
+ // set focus to iview element by default to listen possible keyboard
+ // shortcuts. For embedded applications this is unacceptable as we
+ // don't want to steal focus from the main page nor we don't want
+ // side-effects from focusing (scrollIntoView).
+ getWidgetForPaintable().getElement().focus();
+ }
+
+ getWidgetForPaintable().parentFrame = VView.getParentFrame();
+ }
+
+ private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
+ CLICK_EVENT_IDENTIFIER) {
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ };
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ // NOP The main view never draws caption for its layout
+ }
+
+ @Override
+ public VView getWidgetForPaintable() {
+ return (VView) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VView.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java
index 7b9ece24c9..662b77a7b0 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java
@@ -7,28 +7,23 @@ package com.vaadin.terminal.gwt.client.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.Set;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.DomEvent.Type;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.Frame;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -38,11 +33,9 @@ import com.vaadin.terminal.gwt.client.Console;
import com.vaadin.terminal.gwt.client.Container;
import com.vaadin.terminal.gwt.client.EventId;
import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
/**
@@ -52,7 +45,7 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHan
*/
public class VWindow extends VOverlay implements Container,
ShortcutActionHandlerOwner, ScrollHandler, KeyDownHandler,
- FocusHandler, BlurHandler, BeforeShortcutActionListener, Focusable {
+ FocusHandler, BlurHandler, Focusable {
/**
* Minimum allowed height of a window. This refers to the content area, not
@@ -89,9 +82,9 @@ public class VWindow extends VOverlay implements Container,
public static final int Z_INDEX = 10000;
- private Paintable layout;
+ VPaintableWidget layout;
- private Element contents;
+ Element contents;
private Element header;
@@ -99,7 +92,7 @@ public class VWindow extends VOverlay implements Container,
private Element resizeBox;
- private final FocusableScrollPanel contentPanel = new FocusableScrollPanel();
+ final FocusableScrollPanel contentPanel = new FocusableScrollPanel();
private boolean dragging;
@@ -117,11 +110,11 @@ public class VWindow extends VOverlay implements Container,
private int origH;
- private Element closeBox;
+ Element closeBox;
protected ApplicationConnection client;
- private String id;
+ String id;
ShortcutActionHandler shortcutHandler;
@@ -131,13 +124,13 @@ public class VWindow extends VOverlay implements Container,
/** Last known positiony read from UIDL or updated to application connection */
private int uidlPositionY = -1;
- private boolean vaadinModality = false;
+ boolean vaadinModality = false;
- private boolean resizable = true;
+ boolean resizable = true;
private boolean draggable = true;
- private boolean resizeLazy = false;
+ boolean resizeLazy = false;
private Element modalityCurtain;
private Element draggingCurtain;
@@ -164,23 +157,13 @@ public class VWindow extends VOverlay implements Container,
private String height;
- private boolean immediate;
+ boolean immediate;
private Element wrapper, wrapper2;
- private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
- VPanel.CLICK_EVENT_IDENTIFIER) {
+ boolean visibilityChangesDisabled;
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
- };
-
- private boolean visibilityChangesDisabled;
-
- private int bringToFrontSequence = -1;
+ int bringToFrontSequence = -1;
private VLazyExecutor delayedContentsSizeUpdater = new VLazyExecutor(200,
new ScheduledCommand() {
@@ -285,236 +268,12 @@ public class VWindow extends VOverlay implements Container,
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- id = uidl.getId();
- this.client = client;
-
- // Workaround needed for Testing Tools (GWT generates window DOM
- // slightly different in different browsers).
- DOM.setElementProperty(closeBox, "id", id + "_window_close");
-
- if (uidl.hasAttribute("invisible")) {
- hide();
- return;
- }
-
- if (!uidl.hasAttribute("cached")) {
- if (uidl.getBooleanAttribute("modal") != vaadinModality) {
- setVaadinModality(!vaadinModality);
- }
- if (!isAttached()) {
- setVisible(false); // hide until possible centering
- show();
- }
- if (uidl.getBooleanAttribute("resizable") != resizable) {
- setResizable(!resizable);
- }
- resizeLazy = uidl.hasAttribute(VView.RESIZE_LAZY);
-
- setDraggable(!uidl.hasAttribute("fixedposition"));
-
- // Caption must be set before required header size is measured. If
- // the caption attribute is missing the caption should be cleared.
- setCaption(uidl.getStringAttribute("caption"),
- uidl.getStringAttribute("icon"));
- }
-
- visibilityChangesDisabled = true;
- if (client.updateComponent(this, uidl, false)) {
- return;
- }
- visibilityChangesDisabled = false;
-
- clickEventHandler.handleEventHandlerRegistration(client);
-
- immediate = uidl.hasAttribute("immediate");
-
- setClosable(!uidl.getBooleanAttribute("readonly"));
-
- // Initialize the position form UIDL
- int positionx = uidl.getIntVariable("positionx");
- int positiony = uidl.getIntVariable("positiony");
- if (positionx >= 0 || positiony >= 0) {
- if (positionx < 0) {
- positionx = 0;
- }
- if (positiony < 0) {
- positiony = 0;
- }
- setPopupPosition(positionx, positiony);
- }
-
- boolean showingUrl = false;
- int childIndex = 0;
- UIDL childUidl = uidl.getChildUIDL(childIndex++);
- while ("open".equals(childUidl.getTag())) {
- // TODO multiple opens with the same target will in practice just
- // open the last one - should we fix that somehow?
- final String parsedUri = client.translateVaadinUri(childUidl
- .getStringAttribute("src"));
- if (!childUidl.hasAttribute("name")) {
- final Frame frame = new Frame();
- DOM.setStyleAttribute(frame.getElement(), "width", "100%");
- DOM.setStyleAttribute(frame.getElement(), "height", "100%");
- DOM.setStyleAttribute(frame.getElement(), "border", "0px");
- frame.setUrl(parsedUri);
- contentPanel.setWidget(frame);
- showingUrl = true;
- } else {
- final String target = childUidl.getStringAttribute("name");
- Window.open(parsedUri, target, "");
- }
- childUidl = uidl.getChildUIDL(childIndex++);
- }
-
- final Paintable lo = client.getPaintable(childUidl);
- if (layout != null) {
- if (layout != lo) {
- // remove old
- client.unregisterPaintable(layout);
- contentPanel.remove((Widget) layout);
- // add new
- if (!showingUrl) {
- contentPanel.setWidget((Widget) lo);
- }
- layout = lo;
- }
- } else if (!showingUrl) {
- contentPanel.setWidget((Widget) lo);
- layout = lo;
- }
-
- dynamicWidth = !uidl.hasAttribute("width");
- dynamicHeight = !uidl.hasAttribute("height");
-
- layoutRelativeWidth = uidl.hasAttribute("layoutRelativeWidth");
- layoutRelativeHeight = uidl.hasAttribute("layoutRelativeHeight");
-
- if (dynamicWidth && layoutRelativeWidth) {
- /*
- * Relative layout width, fix window width before rendering (width
- * according to caption)
- */
- setNaturalWidth();
- }
-
- layout.updateFromUIDL(childUidl, client);
- if (!dynamicHeight && layoutRelativeWidth) {
- /*
- * Relative layout width, and fixed height. Must update the size to
- * be able to take scrollbars into account (layout gets narrower
- * space if it is higher than the window) -> only vertical scrollbar
- */
- client.runDescendentsLayout(this);
- }
-
- /*
- * No explicit width is set and the layout does not have relative width
- * so fix the size according to the layout.
- */
- if (dynamicWidth && !layoutRelativeWidth) {
- setNaturalWidth();
- }
-
- if (dynamicHeight && layoutRelativeHeight) {
- // Prevent resizing until height has been fixed
- resizable = false;
- }
-
- // we may have actions and notifications
- if (uidl.getChildCount() > 1) {
- final int cnt = uidl.getChildCount();
- for (int i = 1; i < cnt; i++) {
- childUidl = uidl.getChildUIDL(i);
- if (childUidl.getTag().equals("actions")) {
- if (shortcutHandler == null) {
- shortcutHandler = new ShortcutActionHandler(id, client);
- }
- shortcutHandler.updateActionMap(childUidl);
- } else if (childUidl.getTag().equals("notifications")) {
- for (final Iterator<?> it = childUidl.getChildIterator(); it
- .hasNext();) {
- final UIDL notification = (UIDL) it.next();
- VNotification.showNotification(client, notification);
- }
- }
- }
-
- }
-
- // setting scrollposition must happen after children is rendered
- contentPanel.setScrollPosition(uidl.getIntVariable("scrollTop"));
- contentPanel.setHorizontalScrollPosition(uidl
- .getIntVariable("scrollLeft"));
-
- // Center this window on screen if requested
- // This has to be here because we might not know the content size before
- // everything is painted into the window
- if (uidl.getBooleanAttribute("center")) {
- // mark as centered - this is unset on move/resize
- centered = true;
- center();
- } else {
- // don't try to center the window anymore
- centered = false;
- }
- updateShadowSizeAndPosition();
- setVisible(true);
-
- boolean sizeReduced = false;
- // ensure window is not larger than browser window
- if (getOffsetWidth() > Window.getClientWidth()) {
- setWidth(Window.getClientWidth() + "px");
- sizeReduced = true;
- }
- if (getOffsetHeight() > Window.getClientHeight()) {
- setHeight(Window.getClientHeight() + "px");
- sizeReduced = true;
- }
-
- if (dynamicHeight && layoutRelativeHeight) {
- /*
- * Window height is undefined, layout is 100% high so the layout
- * should define the initial window height but on resize the layout
- * should be as high as the window. We fix the height to deal with
- * this.
- */
-
- int h = contents.getOffsetHeight() + getExtraHeight();
- int w = getElement().getOffsetWidth();
-
- client.updateVariable(id, "height", h, false);
- client.updateVariable(id, "width", w, true);
- }
-
- if (sizeReduced) {
- // If we changed the size we need to update the size of the child
- // component if it is relative (#3407)
- client.runDescendentsLayout(this);
- }
-
- Util.runWebkitOverflowAutoFix(contentPanel.getElement());
-
- client.getView().scrollIntoView(uidl);
-
- if (uidl.hasAttribute("bringToFront")) {
- /*
- * Focus as a side-efect. Will be overridden by
- * ApplicationConnection if another component was focused by the
- * server side.
- */
- contentPanel.focus();
- bringToFrontSequence = uidl.getIntAttribute("bringToFront");
- deferOrdering();
- }
- }
-
/**
* Calling this method will defer ordering algorithm, to order windows based
* on servers bringToFront and modality instructions. Non changed windows
* will be left intact.
*/
- private static void deferOrdering() {
+ static void deferOrdering() {
if (!orderingDefered) {
orderingDefered = true;
Scheduler.get().scheduleFinally(new Command() {
@@ -569,7 +328,7 @@ public class VWindow extends VOverlay implements Container,
}
}
- private void setDraggable(boolean draggable) {
+ void setDraggable(boolean draggable) {
if (this.draggable == draggable) {
return;
}
@@ -580,7 +339,7 @@ public class VWindow extends VOverlay implements Container,
}
private void setCursorProperties() {
- if (!this.draggable) {
+ if (!draggable) {
header.getStyle().setProperty("cursor", "default");
footer.getStyle().setProperty("cursor", "default");
} else {
@@ -589,7 +348,7 @@ public class VWindow extends VOverlay implements Container,
}
}
- private void setNaturalWidth() {
+ void setNaturalWidth() {
/*
* Use max(layout width, window width) i.e layout content width or
* caption width. We remove the previous set width so the width is
@@ -599,19 +358,6 @@ public class VWindow extends VOverlay implements Container,
DOM.setStyleAttribute(getElement(), "width", "");
- String oldHeaderWidth = ""; // Only for IE6
- if (BrowserInfo.get().isIE6()) {
- /*
- * For some reason IE6 has title DIV set to width 100% which
- * interferes with the header measuring. Also IE6 has width set to
- * the contentPanel.
- */
- oldHeaderWidth = headerText.getStyle().getProperty("width");
- DOM.setStyleAttribute(contentPanel.getElement(), "width", "auto");
- DOM.setStyleAttribute(contentPanel.getElement(), "zoom", "1");
- headerText.getStyle().setProperty("width", "auto");
- }
-
// Content
int contentWidth = contentPanel.getElement().getScrollWidth();
contentWidth += getContentAreaToRootDifference();
@@ -622,10 +368,6 @@ public class VWindow extends VOverlay implements Container,
int naturalWidth = (contentWidth > windowCaptionWidth ? contentWidth
: windowCaptionWidth);
- if (BrowserInfo.get().isIE6()) {
- headerText.getStyle().setProperty("width", oldHeaderWidth);
- }
-
setWidth(naturalWidth + "px");
}
@@ -690,42 +432,6 @@ public class VWindow extends VOverlay implements Container,
showModalityCurtain();
}
super.show();
-
- setFF2CaretFixEnabled(true);
- fixFF3OverflowBug();
- }
-
- /** Disable overflow auto with FF3 to fix #1837. */
- private void fixFF3OverflowBug() {
- if (BrowserInfo.get().isFF3()) {
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- DOM.setStyleAttribute(getElement(), "overflow", "");
- }
- });
- }
- }
-
- /**
- * Fix "missing cursor" browser bug workaround for FF2 in Windows and Linux.
- *
- * Calling this method has no effect on other browsers than the ones based
- * on Gecko 1.8
- *
- * @param enable
- */
- private void setFF2CaretFixEnabled(boolean enable) {
- if (BrowserInfo.get().isFF2()) {
- if (enable) {
- Scheduler.get().scheduleDeferred(new Command() {
- public void execute() {
- DOM.setStyleAttribute(getElement(), "overflow", "auto");
- }
- });
- } else {
- DOM.setStyleAttribute(getElement(), "overflow", "");
- }
- }
}
@Override
@@ -736,7 +442,7 @@ public class VWindow extends VOverlay implements Container,
super.hide();
}
- private void setVaadinModality(boolean modality) {
+ void setVaadinModality(boolean modality) {
vaadinModality = modality;
if (vaadinModality) {
if (isAttached()) {
@@ -754,14 +460,6 @@ public class VWindow extends VOverlay implements Container,
}
private void showModalityCurtain() {
- if (BrowserInfo.get().isFF2()) {
- DOM.setStyleAttribute(
- getModalityCurtain(),
- "height",
- DOM.getElementPropertyInt(RootPanel.getBodyElement(),
- "offsetHeight") + "px");
- DOM.setStyleAttribute(getModalityCurtain(), "position", "absolute");
- }
DOM.setStyleAttribute(getModalityCurtain(), "zIndex",
"" + (windowOrder.indexOf(this) + Z_INDEX));
if (isShowing()) {
@@ -781,15 +479,11 @@ public class VWindow extends VOverlay implements Container,
* iframes (etc) do not steal event.
*/
private void showDraggingCurtain() {
- setFF2CaretFixEnabled(false); // makes FF2 slow
-
DOM.appendChild(RootPanel.getBodyElement(), getDraggingCurtain());
}
private void hideDraggingCurtain() {
if (draggingCurtain != null) {
- setFF2CaretFixEnabled(true); // makes FF2 slow
-
DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain);
}
}
@@ -799,15 +493,11 @@ public class VWindow extends VOverlay implements Container,
* that iframes (etc) do not steal event.
*/
private void showResizingCurtain() {
- setFF2CaretFixEnabled(false); // makes FF2 slow
-
DOM.appendChild(RootPanel.getBodyElement(), getResizingCurtain());
}
private void hideResizingCurtain() {
if (resizingCurtain != null) {
- setFF2CaretFixEnabled(true); // makes FF2 slow
-
DOM.removeChild(RootPanel.getBodyElement(), resizingCurtain);
}
}
@@ -843,7 +533,7 @@ public class VWindow extends VOverlay implements Container,
return curtain;
}
- private void setResizable(boolean resizability) {
+ void setResizable(boolean resizability) {
resizable = resizability;
if (resizability) {
DOM.setElementProperty(footer, "className", CLASSNAME + "-footer");
@@ -908,7 +598,7 @@ public class VWindow extends VOverlay implements Container,
if (client != null && header.isOrHasChild(target)) {
// Handle window caption tooltips
- client.handleTooltipEvent(event, this);
+ client.handleWidgetTooltipEvent(event, this);
}
if (resizing || resizeBox == target) {
@@ -1063,8 +753,9 @@ public class VWindow extends VOverlay implements Container,
private void updateContentsSize() {
// Update child widget dimensions
if (client != null) {
- client.handleComponentRelativeSize((Widget) layout);
- client.runDescendentsLayout((HasWidgets) layout);
+ client.handleComponentRelativeSize(layout.getWidgetForPaintable());
+ client.runDescendentsLayout((HasWidgets) layout
+ .getWidgetForPaintable());
}
Util.runWebkitOverflowAutoFix(contentPanel.getElement());
@@ -1100,10 +791,6 @@ public class VWindow extends VOverlay implements Container,
// "width" now contains the new width in pixels
- if (BrowserInfo.get().isIE6()) {
- getElement().getStyle().setProperty("overflow", "hidden");
- }
-
// Apply the new pixel width
getElement().getStyle().setProperty("width", width);
@@ -1117,14 +804,6 @@ public class VWindow extends VOverlay implements Container,
DOM.setStyleAttribute(getElement(), "width", rootWidth + "px");
}
- // IE6 needs the actual inner content width on the content element,
- // otherwise it won't wrap the content properly (no scrollbars
- // appear, content flows out of window)
- if (BrowserInfo.get().isIE6()) {
- DOM.setStyleAttribute(contentPanel.getElement(), "width",
- contentAreaInnerWidth + "px");
- }
-
renderSpace.setWidth(contentAreaInnerWidth);
updateShadowSizeAndPosition();
@@ -1175,7 +854,7 @@ public class VWindow extends VOverlay implements Container,
private int extraH = 0;
- private int getExtraHeight() {
+ int getExtraHeight() {
extraH = header.getOffsetHeight() + footer.getOffsetHeight();
return extraH;
}
@@ -1264,7 +943,7 @@ public class VWindow extends VOverlay implements Container,
while (w != null) {
if (w instanceof Console) {
return true; // allow debug-window clicks
- } else if (w instanceof Paintable) {
+ } else if (w instanceof VPaintableWidget) {
return false;
}
w = w.getParent();
@@ -1312,7 +991,7 @@ public class VWindow extends VOverlay implements Container,
contentPanel.setWidget(newComponent);
}
- public boolean requestLayout(Set<Paintable> child) {
+ public boolean requestLayout(Set<Widget> children) {
if (dynamicWidth && !layoutRelativeWidth) {
setNaturalWidth();
}
@@ -1321,14 +1000,10 @@ public class VWindow extends VOverlay implements Container,
}
updateShadowSizeAndPosition();
// layout size change may affect its available space (scrollbars)
- client.handleComponentRelativeSize((Widget) layout);
+ client.handleComponentRelativeSize(layout.getWidgetForPaintable());
return true;
}
- public void updateCaption(Paintable component, UIDL uidl) {
- // NOP, window has own caption, layout captio not rendered
- }
-
public ShortcutActionHandler getShortcutActionHandler() {
return shortcutHandler;
}
@@ -1350,24 +1025,23 @@ public class VWindow extends VOverlay implements Container,
}
public void onBlur(BlurEvent event) {
- if (client.hasEventListeners(this, EventId.BLUR)) {
+ if (client.hasWidgetEventListeners(this, EventId.BLUR)) {
client.updateVariable(id, EventId.BLUR, "", true);
}
}
public void onFocus(FocusEvent event) {
- if (client.hasEventListeners(this, EventId.FOCUS)) {
+ if (client.hasWidgetEventListeners(this, EventId.FOCUS)) {
client.updateVariable(id, EventId.FOCUS, "", true);
}
}
- public void onBeforeShortcutAction(Event e) {
- // NOP, nothing to update just avoid workaround ( causes excess
- // blur/focus )
- }
-
public void focus() {
contentPanel.focus();
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindowPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VWindowPaintable.java
new file mode 100644
index 0000000000..65ce4a672a
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VWindowPaintable.java
@@ -0,0 +1,296 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.DomEvent.Type;
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Frame;
+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.Util;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
+
+public class VWindowPaintable extends VAbstractPaintableWidgetContainer
+ implements BeforeShortcutActionListener {
+
+ private static final String CLICK_EVENT_IDENTIFIER = VPanelPaintable.CLICK_EVENT_IDENTIFIER;
+
+ private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
+ CLICK_EVENT_IDENTIFIER) {
+
+ @Override
+ protected <H extends EventHandler> HandlerRegistration registerHandler(
+ H handler, Type<H> type) {
+ return getWidgetForPaintable().addDomHandler(handler, type);
+ }
+ };
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().id = uidl.getId();
+ getWidgetForPaintable().client = client;
+
+ // Workaround needed for Testing Tools (GWT generates window DOM
+ // slightly different in different browsers).
+ DOM.setElementProperty(getWidgetForPaintable().closeBox, "id",
+ getWidgetForPaintable().id + "_window_close");
+
+ if (uidl.hasAttribute("invisible")) {
+ getWidgetForPaintable().hide();
+ return;
+ }
+
+ if (!uidl.hasAttribute("cached")) {
+ if (uidl.getBooleanAttribute("modal") != getWidgetForPaintable().vaadinModality) {
+ getWidgetForPaintable().setVaadinModality(
+ !getWidgetForPaintable().vaadinModality);
+ }
+ if (!getWidgetForPaintable().isAttached()) {
+ getWidgetForPaintable().setVisible(false); // hide until
+ // possible centering
+ getWidgetForPaintable().show();
+ }
+ if (uidl.getBooleanAttribute("resizable") != getWidgetForPaintable().resizable) {
+ getWidgetForPaintable().setResizable(
+ !getWidgetForPaintable().resizable);
+ }
+ getWidgetForPaintable().resizeLazy = uidl
+ .hasAttribute(VView.RESIZE_LAZY);
+
+ getWidgetForPaintable().setDraggable(
+ !uidl.hasAttribute("fixedposition"));
+
+ // Caption must be set before required header size is measured. If
+ // the caption attribute is missing the caption should be cleared.
+ getWidgetForPaintable().setCaption(
+ uidl.getStringAttribute("caption"),
+ uidl.getStringAttribute("icon"));
+ }
+
+ getWidgetForPaintable().visibilityChangesDisabled = true;
+ if (client.updateComponent(this, uidl, false)) {
+ return;
+ }
+ getWidgetForPaintable().visibilityChangesDisabled = false;
+
+ clickEventHandler.handleEventHandlerRegistration(client);
+
+ getWidgetForPaintable().immediate = uidl.hasAttribute("immediate");
+
+ getWidgetForPaintable().setClosable(
+ !uidl.getBooleanAttribute("readonly"));
+
+ // Initialize the position form UIDL
+ int positionx = uidl.getIntVariable("positionx");
+ int positiony = uidl.getIntVariable("positiony");
+ if (positionx >= 0 || positiony >= 0) {
+ if (positionx < 0) {
+ positionx = 0;
+ }
+ if (positiony < 0) {
+ positiony = 0;
+ }
+ getWidgetForPaintable().setPopupPosition(positionx, positiony);
+ }
+
+ boolean showingUrl = false;
+ int childIndex = 0;
+ UIDL childUidl = uidl.getChildUIDL(childIndex++);
+ while ("open".equals(childUidl.getTag())) {
+ // TODO multiple opens with the same target will in practice just
+ // open the last one - should we fix that somehow?
+ final String parsedUri = client.translateVaadinUri(childUidl
+ .getStringAttribute("src"));
+ if (!childUidl.hasAttribute("name")) {
+ final Frame frame = new Frame();
+ DOM.setStyleAttribute(frame.getElement(), "width", "100%");
+ DOM.setStyleAttribute(frame.getElement(), "height", "100%");
+ DOM.setStyleAttribute(frame.getElement(), "border", "0px");
+ frame.setUrl(parsedUri);
+ getWidgetForPaintable().contentPanel.setWidget(frame);
+ showingUrl = true;
+ } else {
+ final String target = childUidl.getStringAttribute("name");
+ Window.open(parsedUri, target, "");
+ }
+ childUidl = uidl.getChildUIDL(childIndex++);
+ }
+
+ final VPaintableWidget lo = client.getPaintable(childUidl);
+ if (getWidgetForPaintable().layout != null) {
+ if (getWidgetForPaintable().layout != lo) {
+ // remove old
+ client.unregisterPaintable(getWidgetForPaintable().layout);
+ getWidgetForPaintable().contentPanel
+ .remove(getWidgetForPaintable().layout
+ .getWidgetForPaintable());
+ // add new
+ if (!showingUrl) {
+ getWidgetForPaintable().contentPanel.setWidget(lo
+ .getWidgetForPaintable());
+ }
+ getWidgetForPaintable().layout = lo;
+ }
+ } else if (!showingUrl) {
+ getWidgetForPaintable().contentPanel.setWidget(lo
+ .getWidgetForPaintable());
+ getWidgetForPaintable().layout = lo;
+ }
+
+ getWidgetForPaintable().dynamicWidth = !uidl.hasAttribute("width");
+ getWidgetForPaintable().dynamicHeight = !uidl.hasAttribute("height");
+
+ getWidgetForPaintable().layoutRelativeWidth = uidl
+ .hasAttribute("layoutRelativeWidth");
+ getWidgetForPaintable().layoutRelativeHeight = uidl
+ .hasAttribute("layoutRelativeHeight");
+
+ if (getWidgetForPaintable().dynamicWidth
+ && getWidgetForPaintable().layoutRelativeWidth) {
+ /*
+ * Relative layout width, fix window width before rendering (width
+ * according to caption)
+ */
+ getWidgetForPaintable().setNaturalWidth();
+ }
+
+ getWidgetForPaintable().layout.updateFromUIDL(childUidl, client);
+ if (!getWidgetForPaintable().dynamicHeight
+ && getWidgetForPaintable().layoutRelativeWidth) {
+ /*
+ * Relative layout width, and fixed height. Must update the size to
+ * be able to take scrollbars into account (layout gets narrower
+ * space if it is higher than the window) -> only vertical scrollbar
+ */
+ client.runDescendentsLayout(getWidgetForPaintable());
+ }
+
+ /*
+ * No explicit width is set and the layout does not have relative width
+ * so fix the size according to the layout.
+ */
+ if (getWidgetForPaintable().dynamicWidth
+ && !getWidgetForPaintable().layoutRelativeWidth) {
+ getWidgetForPaintable().setNaturalWidth();
+ }
+
+ if (getWidgetForPaintable().dynamicHeight
+ && getWidgetForPaintable().layoutRelativeHeight) {
+ // Prevent resizing until height has been fixed
+ getWidgetForPaintable().resizable = false;
+ }
+
+ // we may have actions and notifications
+ if (uidl.getChildCount() > 1) {
+ final int cnt = uidl.getChildCount();
+ for (int i = 1; i < cnt; i++) {
+ childUidl = uidl.getChildUIDL(i);
+ if (childUidl.getTag().equals("actions")) {
+ if (getWidgetForPaintable().shortcutHandler == null) {
+ getWidgetForPaintable().shortcutHandler = new ShortcutActionHandler(
+ getId(), client);
+ }
+ getWidgetForPaintable().shortcutHandler
+ .updateActionMap(childUidl);
+ }
+ }
+
+ }
+
+ // setting scrollposition must happen after children is rendered
+ getWidgetForPaintable().contentPanel.setScrollPosition(uidl
+ .getIntVariable("scrollTop"));
+ getWidgetForPaintable().contentPanel.setHorizontalScrollPosition(uidl
+ .getIntVariable("scrollLeft"));
+
+ // Center this window on screen if requested
+ // This has to be here because we might not know the content size before
+ // everything is painted into the window
+ if (uidl.getBooleanAttribute("center")) {
+ // mark as centered - this is unset on move/resize
+ getWidgetForPaintable().centered = true;
+ getWidgetForPaintable().center();
+ } else {
+ // don't try to center the window anymore
+ getWidgetForPaintable().centered = false;
+ }
+ getWidgetForPaintable().updateShadowSizeAndPosition();
+ getWidgetForPaintable().setVisible(true);
+
+ boolean sizeReduced = false;
+ // ensure window is not larger than browser window
+ if (getWidgetForPaintable().getOffsetWidth() > Window.getClientWidth()) {
+ getWidgetForPaintable().setWidth(Window.getClientWidth() + "px");
+ sizeReduced = true;
+ }
+ if (getWidgetForPaintable().getOffsetHeight() > Window
+ .getClientHeight()) {
+ getWidgetForPaintable().setHeight(Window.getClientHeight() + "px");
+ sizeReduced = true;
+ }
+
+ if (getWidgetForPaintable().dynamicHeight
+ && getWidgetForPaintable().layoutRelativeHeight) {
+ /*
+ * Window height is undefined, layout is 100% high so the layout
+ * should define the initial window height but on resize the layout
+ * should be as high as the window. We fix the height to deal with
+ * this.
+ */
+
+ int h = getWidgetForPaintable().contents.getOffsetHeight()
+ + getWidgetForPaintable().getExtraHeight();
+ int w = getWidgetForPaintable().getElement().getOffsetWidth();
+
+ client.updateVariable(getId(), "height", h, false);
+ client.updateVariable(getId(), "width", w, true);
+ }
+
+ if (sizeReduced) {
+ // If we changed the size we need to update the size of the child
+ // component if it is relative (#3407)
+ client.runDescendentsLayout(getWidgetForPaintable());
+ }
+
+ Util.runWebkitOverflowAutoFix(getWidgetForPaintable().contentPanel
+ .getElement());
+
+ client.getView().getWidgetForPaintable().scrollIntoView(uidl);
+
+ if (uidl.hasAttribute("bringToFront")) {
+ /*
+ * Focus as a side-efect. Will be overridden by
+ * ApplicationConnection if another component was focused by the
+ * server side.
+ */
+ getWidgetForPaintable().contentPanel.focus();
+ getWidgetForPaintable().bringToFrontSequence = uidl
+ .getIntAttribute("bringToFront");
+ VWindow.deferOrdering();
+ }
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ // NOP, window has own caption, layout captio not rendered
+ }
+
+ public void onBeforeShortcutAction(Event e) {
+ // NOP, nothing to update just avoid workaround ( causes excess
+ // blur/focus )
+ }
+
+ @Override
+ public VWindow getWidgetForPaintable() {
+ return (VWindow) super.getWidgetForPaintable();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VWindow.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java
index 6280031d84..4d752d4527 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java
@@ -9,7 +9,7 @@ import com.google.gwt.user.client.Command;
import com.vaadin.event.Transferable;
import com.vaadin.event.dd.DropTarget;
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.UIDL;
public abstract class VAbstractDropHandler implements VDropHandler {
@@ -129,6 +129,6 @@ public abstract class VAbstractDropHandler implements VDropHandler {
* side counterpart of the Paintable is expected to implement
* {@link DropTarget} interface.
*/
- public abstract Paintable getPaintable();
+ public abstract VPaintableWidget getPaintable();
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java
index dbeff243a8..b86a404678 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java
@@ -24,9 +24,9 @@ import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ValueMap;
/**
@@ -333,10 +333,10 @@ public class VDragAndDropManager {
}
private void addActiveDragSourceStyleName() {
- Paintable dragSource = currentDrag.getTransferable()
+ VPaintableWidget dragSource = currentDrag.getTransferable()
.getDragSource();
- ((Widget) dragSource)
- .addStyleName(ACTIVE_DRAG_SOURCE_STYLENAME);
+ dragSource.getWidgetForPaintable().addStyleName(
+ ACTIVE_DRAG_SOURCE_STYLENAME);
}
};
@@ -499,8 +499,8 @@ public class VDragAndDropManager {
* handled. E.g. hidden on start, removed in drophandler ->
* would flicker in case removed eagerly.
*/
- final Paintable dragSource = currentDrag.getTransferable()
- .getDragSource();
+ final VPaintableWidget dragSource = currentDrag
+ .getTransferable().getDragSource();
final ApplicationConnection client = currentDropHandler
.getApplicationConnection();
Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
@@ -543,8 +543,9 @@ public class VDragAndDropManager {
}
- private void removeActiveDragSourceStyleName(Paintable dragSource) {
- ((Widget) dragSource).removeStyleName(ACTIVE_DRAG_SOURCE_STYLENAME);
+ private void removeActiveDragSourceStyleName(VPaintableWidget dragSource) {
+ dragSource.getWidgetForPaintable().removeStyleName(
+ ACTIVE_DRAG_SOURCE_STYLENAME);
}
private void clearDragElement() {
@@ -578,7 +579,7 @@ public class VDragAndDropManager {
if (currentDropHandler == null) {
return;
}
- Paintable paintable = currentDropHandler.getPaintable();
+ VPaintableWidget paintable = currentDropHandler.getPaintable();
ApplicationConnection client = currentDropHandler
.getApplicationConnection();
/*
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java
index 1278ed7fdb..2be75ae3d9 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java
@@ -3,8 +3,9 @@
*/
package com.vaadin.terminal.gwt.client.ui.dd;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
/**
* TODO Javadoc!
@@ -16,13 +17,15 @@ final public class VDragSourceIs extends VAcceptCriterion {
@Override
protected boolean accept(VDragEvent drag, UIDL configuration) {
try {
- Paintable component = drag.getTransferable().getDragSource();
+ VPaintableWidget component = drag.getTransferable().getDragSource();
int c = configuration.getIntAttribute("c");
for (int i = 0; i < c; i++) {
String requiredPid = configuration
.getStringAttribute("component" + i);
- Paintable paintable = VDragAndDropManager.get()
- .getCurrentDropHandler().getApplicationConnection()
+ VDropHandler currentDropHandler = VDragAndDropManager.get()
+ .getCurrentDropHandler();
+ VPaintableWidget paintable = (VPaintableWidget) VPaintableMap
+ .get(currentDropHandler.getApplicationConnection())
.getPaintable(requiredPid);
if (paintable == component) {
return true;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java
index a597e9ed30..d84dea4833 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java
@@ -4,7 +4,7 @@
package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
/**
* Vaadin Widgets that want to receive something via drag and drop implement
@@ -61,7 +61,7 @@ public interface VDropHandler {
/**
* Returns the Paintable into which this DragHandler is associated
*/
- public Paintable getPaintable();
+ public VPaintableWidget getPaintable();
/**
* Returns the application connection to which this {@link VDropHandler}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java
index 0195862431..48f748a4f3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java
@@ -3,13 +3,13 @@
*/
package com.vaadin.terminal.gwt.client.ui.dd;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
/**
* Used to detect Widget from widget tree that has {@link #getDropHandler()}
*
* Decide whether to get rid of this class. If so, {@link VAbstractDropHandler}
- * must extend {@link Paintable}.
+ * must extend {@link VPaintableWidget}.
*
*/
public interface VHasDropHandler {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java
index 58dc0d3956..3ea7d1a482 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java
@@ -6,8 +6,9 @@
*/
package com.vaadin.terminal.gwt.client.ui.dd;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
final public class VIsOverId extends VAcceptCriterion {
@@ -16,10 +17,13 @@ final public class VIsOverId extends VAcceptCriterion {
try {
String pid = configuration.getStringAttribute("s");
- Paintable paintable = VDragAndDropManager.get()
- .getCurrentDropHandler().getPaintable();
- String pid2 = VDragAndDropManager.get().getCurrentDropHandler()
- .getApplicationConnection().getPid(paintable);
+ VDropHandler currentDropHandler = VDragAndDropManager.get()
+ .getCurrentDropHandler();
+ VPaintableWidget paintable = currentDropHandler.getPaintable();
+ VPaintableMap paintableMap = VPaintableMap.get(currentDropHandler
+ .getApplicationConnection());
+
+ String pid2 = paintableMap.getPid(paintable);
if (pid2.equals(pid)) {
Object searchedId = drag.getDropDetails().get("itemIdOver");
String[] stringArrayAttribute = configuration
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java
index ada7a3c78a..16de428d9c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java
@@ -6,8 +6,9 @@
*/
package com.vaadin.terminal.gwt.client.ui.dd;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
final public class VItemIdIs extends VAcceptCriterion {
@@ -15,9 +16,13 @@ final public class VItemIdIs extends VAcceptCriterion {
protected boolean accept(VDragEvent drag, UIDL configuration) {
try {
String pid = configuration.getStringAttribute("s");
- Paintable dragSource = drag.getTransferable().getDragSource();
- String pid2 = VDragAndDropManager.get().getCurrentDropHandler()
- .getApplicationConnection().getPid(dragSource);
+ VPaintableWidget dragSource = drag.getTransferable()
+ .getDragSource();
+ VDropHandler currentDropHandler = VDragAndDropManager.get()
+ .getCurrentDropHandler();
+ String pid2 = VPaintableMap.get(
+ currentDropHandler.getApplicationConnection()).getPid(
+ dragSource);
if (pid2.equals(pid)) {
Object searchedId = drag.getTransferable().getData("itemId");
String[] stringArrayAttribute = configuration
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java
index ff4c4f1d35..55c1110546 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java
@@ -6,15 +6,15 @@
*/
package com.vaadin.terminal.gwt.client.ui.dd;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.UIDL;
final public class VSourceIsTarget extends VAcceptCriterion {
@Override
protected boolean accept(VDragEvent drag, UIDL configuration) {
- Paintable dragSource = drag.getTransferable().getDragSource();
- Paintable paintable = VDragAndDropManager.get().getCurrentDropHandler()
+ VPaintableWidget dragSource = drag.getTransferable().getDragSource();
+ VPaintableWidget paintable = VDragAndDropManager.get().getCurrentDropHandler()
.getPaintable();
return paintable == dragSource;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java
index fe51ea82e4..f81567f906 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java
@@ -8,7 +8,7 @@ import java.util.HashMap;
import java.util.Map;
import com.vaadin.event.dd.DragSource;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
/**
* Client side counterpart for Transferable in com.vaadin.event.Transferable
@@ -16,7 +16,7 @@ import com.vaadin.terminal.gwt.client.Paintable;
*/
public class VTransferable {
- private Paintable component;
+ private VPaintableWidget component;
private final Map<String, Object> variables = new HashMap<String, Object>();
@@ -26,7 +26,7 @@ public class VTransferable {
*
* @return the component
*/
- public Paintable getDragSource() {
+ public VPaintableWidget getDragSource() {
return component;
}
@@ -41,7 +41,7 @@ public class VTransferable {
* @param component
* the component to set
*/
- public void setDragSource(Paintable component) {
+ public void setDragSource(VPaintableWidget component) {
this.component = component;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java b/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java
new file mode 100644
index 0000000000..8828582b57
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java
@@ -0,0 +1,70 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.label;
+
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VTooltip;
+
+public class VLabel extends HTML {
+
+ public static final String CLASSNAME = "v-label";
+ private static final String CLASSNAME_UNDEFINED_WIDTH = "v-label-undef-w";
+
+ private int verticalPaddingBorder = 0;
+ private int horizontalPaddingBorder = 0;
+
+ public VLabel() {
+ super();
+ setStyleName(CLASSNAME);
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
+ }
+
+ public VLabel(String text) {
+ super(text);
+ setStyleName(CLASSNAME);
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ if (event.getTypeInt() == Event.ONLOAD) {
+ Util.notifyParentOfSizeChange(this, true);
+ event.stopPropagation();
+ return;
+ }
+ }
+
+ @Override
+ public void setHeight(String height) {
+ verticalPaddingBorder = Util.setHeightExcludingPaddingAndBorder(this,
+ height, verticalPaddingBorder);
+ }
+
+ @Override
+ public void setWidth(String width) {
+ horizontalPaddingBorder = Util.setWidthExcludingPaddingAndBorder(this,
+ width, horizontalPaddingBorder);
+ if (width == null || width.equals("")) {
+ setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, true);
+ } else {
+ setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, false);
+ }
+ }
+
+ @Override
+ public void setText(String text) {
+ if (BrowserInfo.get().isIE8()) {
+ // #3983 - IE8 incorrectly replaces \n with <br> so we do the
+ // escaping manually and set as HTML
+ super.setHTML(Util.escapeHTML(text));
+ } else {
+ super.setText(text);
+ }
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/label/VLabelPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/label/VLabelPaintable.java
new file mode 100644
index 0000000000..c57f705c75
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/label/VLabelPaintable.java
@@ -0,0 +1,71 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui.label;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.PreElement;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.ui.VAbstractPaintableWidget;
+
+public class VLabelPaintable extends VAbstractPaintableWidget {
+ public VLabelPaintable() {
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ boolean sinkOnloads = false;
+
+ final String mode = uidl.getStringAttribute("mode");
+ if (mode == null || "text".equals(mode)) {
+ getWidgetForPaintable().setText(uidl.getChildString(0));
+ } else if ("pre".equals(mode)) {
+ PreElement preElement = Document.get().createPreElement();
+ preElement.setInnerText(uidl.getChildUIDL(0).getChildString(0));
+ // clear existing content
+ getWidgetForPaintable().setHTML("");
+ // add preformatted text to dom
+ getWidgetForPaintable().getElement().appendChild(preElement);
+ } else if ("uidl".equals(mode)) {
+ getWidgetForPaintable().setHTML(uidl.getChildrenAsXML());
+ } else if ("xhtml".equals(mode)) {
+ UIDL content = uidl.getChildUIDL(0).getChildUIDL(0);
+ if (content.getChildCount() > 0) {
+ getWidgetForPaintable().setHTML(content.getChildString(0));
+ } else {
+ getWidgetForPaintable().setHTML("");
+ }
+ sinkOnloads = true;
+ } else if ("xml".equals(mode)) {
+ getWidgetForPaintable().setHTML(
+ uidl.getChildUIDL(0).getChildString(0));
+ } else if ("raw".equals(mode)) {
+ getWidgetForPaintable().setHTML(
+ uidl.getChildUIDL(0).getChildString(0));
+ sinkOnloads = true;
+ } else {
+ getWidgetForPaintable().setText("");
+ }
+ if (sinkOnloads) {
+ Util.sinkOnloadForImages(getWidgetForPaintable().getElement());
+ }
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VLabel.class);
+ }
+
+ @Override
+ public VLabel getWidgetForPaintable() {
+ return (VLabel) super.getWidgetForPaintable();
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java
index 2ca58a38c2..9b38ba23ae 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java
@@ -3,6 +3,7 @@
*/
package com.vaadin.terminal.gwt.client.ui.layout;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -17,8 +18,8 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.VMarginInfo;
public abstract class CellBasedLayout extends ComplexPanel implements Container {
@@ -27,7 +28,7 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
protected ApplicationConnection client = null;
- protected DivElement root;
+ public DivElement root;
public static final int ORIENTATION_VERTICAL = 0;
public static final int ORIENTATION_HORIZONTAL = 1;
@@ -39,15 +40,15 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
protected final Spacing spacingFromCSS = new Spacing(12, 12);
protected final Spacing activeSpacing = new Spacing(0, 0);
- private boolean dynamicWidth;
+ boolean dynamicWidth;
- private boolean dynamicHeight;
+ boolean dynamicHeight;
private final DivElement clearElement = Document.get().createDivElement();
private String lastStyleName = "";
- private boolean marginsNeedsRecalculation = false;
+ boolean marginsNeedsRecalculation = false;
protected String STYLENAME_SPACING = "";
protected String STYLENAME_MARGIN_TOP = "";
@@ -104,32 +105,6 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
return widgetToComponentContainer.containsKey(component);
}
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- this.client = client;
-
- // Only non-cached UIDL:s can introduce changes
- if (uidl.getBooleanAttribute("cached")) {
- return;
- }
-
- /**
- * Margin and spacind detection depends on classNames and must be set
- * before setting size. Here just update the details from UIDL and from
- * overridden setStyleName run actual margin detections.
- */
- updateMarginAndSpacingInfo(uidl);
-
- /*
- * This call should be made first. Ensure correct implementation, handle
- * size etc.
- */
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- handleDynamicDimensions(uidl);
- }
-
@Override
public void setStyleName(String styleName) {
super.setStyleName(styleName);
@@ -158,27 +133,6 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
}
}
- private void handleDynamicDimensions(UIDL uidl) {
- String w = uidl.hasAttribute("width") ? uidl
- .getStringAttribute("width") : "";
-
- String h = uidl.hasAttribute("height") ? uidl
- .getStringAttribute("height") : "";
-
- if (w.equals("")) {
- dynamicWidth = true;
- } else {
- dynamicWidth = false;
- }
-
- if (h.equals("")) {
- dynamicHeight = true;
- } else {
- dynamicHeight = false;
- }
-
- }
-
@Override
public void setHeight(String height) {
super.setHeight(height);
@@ -194,7 +148,7 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
}
}
- protected void addOrMoveChild(ChildComponentContainer childComponent,
+ public void addOrMoveChild(ChildComponentContainer childComponent,
int position) {
if (childComponent.getParent() == this) {
if (getWidgetIndex(childComponent) != position) {
@@ -234,33 +188,22 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
}
- protected ChildComponentContainer getComponentContainer(Widget child) {
+ public Collection<ChildComponentContainer> getComponentContainers() {
+ return widgetToComponentContainer.values();
+ }
+
+ public ChildComponentContainer getComponentContainer(Widget child) {
return widgetToComponentContainer.get(child);
}
- protected boolean isDynamicWidth() {
+ public boolean isDynamicWidth() {
return dynamicWidth;
}
- protected boolean isDynamicHeight() {
+ public boolean isDynamicHeight() {
return dynamicHeight;
}
- private void updateMarginAndSpacingInfo(UIDL uidl) {
- if (!uidl.hasAttribute("invisible")) {
- int bitMask = uidl.getIntAttribute("margins");
- if (activeMarginsInfo.getBitMask() != bitMask) {
- activeMarginsInfo = new VMarginInfo(bitMask);
- marginsNeedsRecalculation = true;
- }
- boolean spacing = uidl.getBooleanAttribute("spacing");
- if (spacing != spacingEnabled) {
- marginsNeedsRecalculation = true;
- spacingEnabled = spacing;
- }
- }
- }
-
private static DivElement measurement;
private static DivElement measurement2;
private static DivElement measurement3;
@@ -341,7 +284,7 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
return (ChildComponentContainer) getChildren().get(0);
}
- protected void removeChildrenAfter(int pos) {
+ public void removeChildrenAfter(int pos) {
// Remove all children after position "pos" but leave the clear element
// in place
@@ -375,8 +318,9 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
widgetToComponentContainer.remove(widget);
remove(child);
if (!relocated) {
- Paintable p = (Paintable) widget;
- client.unregisterPaintable(p);
+ VPaintableMap paintableMap = VPaintableMap.get(client);
+ VPaintableWidget p = paintableMap.getPaintable(widget);
+ paintableMap.unregisterPaintable(p);
}
}
@@ -389,8 +333,10 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
return;
}
- componentContainer.setWidget(newComponent);
- client.unregisterPaintable((Paintable) oldComponent);
+ componentContainer.setPaintable(VPaintableMap.get(client).getPaintable(
+ newComponent));
+ client.unregisterPaintable(VPaintableMap.get(client).getPaintable(
+ oldComponent));
widgetToComponentContainer.put(newComponent, componentContainer);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayoutPaintable.java
new file mode 100644
index 0000000000..5fc74c056e
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayoutPaintable.java
@@ -0,0 +1,81 @@
+package com.vaadin.terminal.gwt.client.ui.layout;
+
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.VAbstractPaintableWidgetContainer;
+import com.vaadin.terminal.gwt.client.ui.VMarginInfo;
+
+public abstract class CellBasedLayoutPaintable extends
+ VAbstractPaintableWidgetContainer {
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().client = client;
+
+ // Only non-cached UIDL:s can introduce changes
+ if (uidl.getBooleanAttribute("cached")) {
+ return;
+ }
+
+ /**
+ * Margin and spacind detection depends on classNames and must be set
+ * before setting size. Here just update the details from UIDL and from
+ * overridden setStyleName run actual margin detections.
+ */
+ updateMarginAndSpacingInfo(uidl);
+
+ /*
+ * This call should be made first. Ensure correct implementation, handle
+ * size etc.
+ */
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ handleDynamicDimensions(uidl);
+ }
+
+ private void handleDynamicDimensions(UIDL uidl) {
+ String w = uidl.hasAttribute("width") ? uidl
+ .getStringAttribute("width") : "";
+
+ String h = uidl.hasAttribute("height") ? uidl
+ .getStringAttribute("height") : "";
+
+ if (w.equals("")) {
+ getWidgetForPaintable().dynamicWidth = true;
+ } else {
+ getWidgetForPaintable().dynamicWidth = false;
+ }
+
+ if (h.equals("")) {
+ getWidgetForPaintable().dynamicHeight = true;
+ } else {
+ getWidgetForPaintable().dynamicHeight = false;
+ }
+
+ }
+
+ void updateMarginAndSpacingInfo(UIDL uidl) {
+ if (!uidl.hasAttribute("invisible")) {
+ int bitMask = uidl.getIntAttribute("margins");
+ if (getWidgetForPaintable().activeMarginsInfo.getBitMask() != bitMask) {
+ getWidgetForPaintable().activeMarginsInfo = new VMarginInfo(
+ bitMask);
+ getWidgetForPaintable().marginsNeedsRecalculation = true;
+ }
+ boolean spacing = uidl.getBooleanAttribute("spacing");
+ if (spacing != getWidgetForPaintable().spacingEnabled) {
+ getWidgetForPaintable().marginsNeedsRecalculation = true;
+ getWidgetForPaintable().spacingEnabled = spacing;
+ }
+ }
+ }
+
+ @Override
+ protected abstract CellBasedLayout createWidget();
+
+ @Override
+ public CellBasedLayout getWidgetForPaintable() {
+ return (CellBasedLayout) super.getWidgetForPaintable();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java b/src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java
index 36d18306fa..92464cd459 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java
@@ -9,20 +9,17 @@ import java.util.NoSuchElementException;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.BorderStyle;
-import com.google.gwt.dom.client.TableElement;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.AlignmentInfo;
public class ChildComponentContainer extends Panel {
@@ -71,38 +68,22 @@ public class ChildComponentContainer extends Panel {
private VCaption caption = null;
private DivElement containerDIV;
private DivElement widgetDIV;
+ private VPaintableWidget paintable;
private Widget widget;
private FloatSize relativeSize = null;
- public ChildComponentContainer(Widget widget, int orientation) {
+ public ChildComponentContainer(VPaintableWidget child, int orientation) {
super();
containerDIV = Document.get().createDivElement();
widgetDIV = Document.get().createDivElement();
- if (BrowserInfo.get().isFF2()) {
- // Style style = widgetDIV.getStyle();
- // FF2 chokes on some floats very easily. Measuring size escpecially
- // becomes terribly slow
- TableElement tableEl = Document.get().createTableElement();
- tableEl.setInnerHTML("<tbody><tr><td><div></div></td></tr></tbody>");
- DivElement div = (DivElement) tableEl.getFirstChildElement()
- .getFirstChildElement().getFirstChildElement()
- .getFirstChildElement();
- tableEl.setCellPadding(0);
- tableEl.setCellSpacing(0);
- tableEl.setBorder(0);
- div.getStyle().setProperty("padding", "0");
-
- setElement(tableEl);
- containerDIV = div;
- } else {
- setFloat(widgetDIV, "left");
- setElement(containerDIV);
- containerDIV.getStyle().setProperty("height", "0");
- containerDIV.getStyle().setProperty("width", "0px");
- containerDIV.getStyle().setProperty("overflow", "hidden");
- }
+
+ setFloat(widgetDIV, "left");
+ setElement(containerDIV);
+ containerDIV.getStyle().setProperty("height", "0");
+ containerDIV.getStyle().setProperty("width", "0px");
+ containerDIV.getStyle().setProperty("overflow", "hidden");
if (BrowserInfo.get().isIE()) {
/*
@@ -119,11 +100,15 @@ public class ChildComponentContainer extends Panel {
setOrientation(orientation);
- setWidget(widget);
+ setPaintable(child);
+ }
+ public void setPaintable(VPaintableWidget childPaintable) {
+ paintable = childPaintable;
+ setWidget(childPaintable.getWidgetForPaintable());
}
- public void setWidget(Widget w) {
+ private void setWidget(Widget w) {
// Validate
if (w == widget) {
return;
@@ -207,7 +192,7 @@ public class ChildComponentContainer extends Panel {
if (fixedWidth < 0 && BrowserInfo.get().isOpera()) {
setUnlimitedContainerWidth();
}
- ((Paintable) widget).updateFromUIDL(childUIDL, client);
+ paintable.updateFromUIDL(childUIDL, client);
}
public void setUnlimitedContainerWidth() {
@@ -224,36 +209,6 @@ public class ChildComponentContainer extends Panel {
* does not include
*/
int w = Util.getRequiredWidth(widgetDIV);
-
- // IE7 ignores the width of the content if there's a border (#3915)
- if (BrowserInfo.get().isIE7()) {
- // Also read the inner width of the target element
- int clientWidth = widget.getElement().getClientWidth();
-
- // If the widths are different, there might be a border involved and
- // then the width should be calculated without borders
- if (w != clientWidth) {
- // Remember old border style and remove current border
- Style style = widget.getElement().getStyle();
- String oldBorderStyle = style.getBorderStyle();
- style.setBorderStyle(BorderStyle.NONE);
-
- // Calculate width without borders
- int newWidth = Util.getRequiredWidth(widgetDIV);
-
- // Restore old border style
- style.setProperty("borderStyle", oldBorderStyle);
-
- // Borders triggered the bug if the element is wider without
- // borders
- if (newWidth > w) {
- // Use new measured width + the border width calculated as
- // the difference between previous inner and outer widths
- w = newWidth + (w - clientWidth);
- }
- }
- }
-
int h = Util.getRequiredHeight(widgetDIV);
widgetSize.setWidth(w);
@@ -454,7 +409,7 @@ public class ChildComponentContainer extends Panel {
VCaption newCaption = caption;
if (newCaption == null) {
- newCaption = new VCaption((Paintable) widget, client);
+ newCaption = new VCaption(paintable, client);
// Set initial height to avoid Safari flicker
newCaption.setHeight("18px");
// newCaption.setHeight(newCaption.getHeight()); // This might
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java
index bf0a423474..a586929d13 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java
@@ -17,7 +17,6 @@ import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -27,12 +26,10 @@ import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
import com.vaadin.terminal.gwt.client.ui.Field;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
-import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
/**
@@ -41,9 +38,8 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHan
* @author Vaadin Ltd.
*
*/
-public class VRichTextArea extends Composite implements Paintable, Field,
- ChangeHandler, BlurHandler, KeyPressHandler, KeyDownHandler,
- BeforeShortcutActionListener, Focusable {
+public class VRichTextArea extends Composite implements Field, ChangeHandler,
+ BlurHandler, KeyPressHandler, KeyDownHandler, Focusable {
/**
* The input node CSS classname.
@@ -54,13 +50,13 @@ public class VRichTextArea extends Composite implements Paintable, Field,
protected ApplicationConnection client;
- private boolean immediate = false;
+ boolean immediate = false;
- private RichTextArea rta;
+ RichTextArea rta;
private VRichTextToolbar formatter;
- private HTML html = new HTML();
+ HTML html = new HTML();
private final FlowPanel fp = new FlowPanel();
@@ -69,15 +65,15 @@ public class VRichTextArea extends Composite implements Paintable, Field,
private int extraHorizontalPixels = -1;
private int extraVerticalPixels = -1;
- private int maxLength = -1;
+ int maxLength = -1;
private int toolbarNaturalWidth = 500;
- private HandlerRegistration keyPressHandler;
+ HandlerRegistration keyPressHandler;
private ShortcutActionHandlerOwner hasShortcutActionHandler;
- private String currentValue = "";
+ String currentValue = "";
private boolean readOnly = false;
@@ -127,48 +123,7 @@ public class VRichTextArea extends Composite implements Paintable, Field,
}
}
- public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
- this.client = client;
- id = uidl.getId();
-
- if (uidl.hasVariable("text")) {
- currentValue = uidl.getStringVariable("text");
- if (rta.isAttached()) {
- rta.setHTML(currentValue);
- } else {
- html.setHTML(currentValue);
- }
- }
- if (!uidl.hasAttribute("cached")) {
- setEnabled(!uidl.getBooleanAttribute("disabled"));
- }
-
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- setReadOnly(uidl.getBooleanAttribute("readonly"));
- immediate = uidl.getBooleanAttribute("immediate");
- int newMaxLength = uidl.hasAttribute("maxLength") ? uidl
- .getIntAttribute("maxLength") : -1;
- if (newMaxLength >= 0) {
- if (maxLength == -1) {
- keyPressHandler = rta.addKeyPressHandler(this);
- }
- maxLength = newMaxLength;
- } else if (maxLength != -1) {
- getElement().setAttribute("maxlength", "");
- maxLength = -1;
- keyPressHandler.removeHandler();
- }
-
- if (uidl.hasAttribute("selectAll")) {
- selectAll();
- }
-
- }
-
- private void selectAll() {
+ void selectAll() {
/*
* There is a timing issue if trying to select all immediately on first
* render. Simple deferred command is not enough. Using Timer with
@@ -190,7 +145,7 @@ public class VRichTextArea extends Composite implements Paintable, Field,
}.schedule(320);
}
- private void setReadOnly(boolean b) {
+ void setReadOnly(boolean b) {
if (isReadOnly() != b) {
swapEditableArea();
readOnly = b;
@@ -346,7 +301,8 @@ public class VRichTextArea extends Composite implements Paintable, Field,
if (shortcutHandler != null) {
shortcutHandler
.handleKeyboardEvent(com.google.gwt.user.client.Event
- .as(event.getNativeEvent()), this);
+ .as(event.getNativeEvent()),
+ VPaintableMap.get(client).getPaintable(this));
}
}
@@ -364,10 +320,6 @@ public class VRichTextArea extends Composite implements Paintable, Field,
return hasShortcutActionHandler;
}
- public void onBeforeShortcutAction(Event e) {
- synchronizeContentToServer();
- }
-
public int getTabIndex() {
return rta.getTabIndex();
}
@@ -394,4 +346,8 @@ public class VRichTextArea extends Composite implements Paintable, Field,
rta.setTabIndex(index);
}
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextAreaPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextAreaPaintable.java
new file mode 100644
index 0000000000..1dadf8cc17
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextAreaPaintable.java
@@ -0,0 +1,76 @@
+package com.vaadin.terminal.gwt.client.ui.richtextarea;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
+import com.vaadin.terminal.gwt.client.ui.VAbstractPaintableWidget;
+
+public class VRichTextAreaPaintable extends VAbstractPaintableWidget implements
+ BeforeShortcutActionListener {
+
+ public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
+ getWidgetForPaintable().client = client;
+ getWidgetForPaintable().id = uidl.getId();
+
+ if (uidl.hasVariable("text")) {
+ getWidgetForPaintable().currentValue = uidl
+ .getStringVariable("text");
+ if (getWidgetForPaintable().rta.isAttached()) {
+ getWidgetForPaintable().rta
+ .setHTML(getWidgetForPaintable().currentValue);
+ } else {
+ getWidgetForPaintable().html
+ .setHTML(getWidgetForPaintable().currentValue);
+ }
+ }
+ if (!uidl.hasAttribute("cached")) {
+ getWidgetForPaintable().setEnabled(
+ !uidl.getBooleanAttribute("disabled"));
+ }
+
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ getWidgetForPaintable().setReadOnly(
+ uidl.getBooleanAttribute("readonly"));
+ getWidgetForPaintable().immediate = uidl
+ .getBooleanAttribute("immediate");
+ int newMaxLength = uidl.hasAttribute("maxLength") ? uidl
+ .getIntAttribute("maxLength") : -1;
+ if (newMaxLength >= 0) {
+ if (getWidgetForPaintable().maxLength == -1) {
+ getWidgetForPaintable().keyPressHandler = getWidgetForPaintable().rta
+ .addKeyPressHandler(getWidgetForPaintable());
+ }
+ getWidgetForPaintable().maxLength = newMaxLength;
+ } else if (getWidgetForPaintable().maxLength != -1) {
+ getWidgetForPaintable().getElement().setAttribute("maxlength", "");
+ getWidgetForPaintable().maxLength = -1;
+ getWidgetForPaintable().keyPressHandler.removeHandler();
+ }
+
+ if (uidl.hasAttribute("selectAll")) {
+ getWidgetForPaintable().selectAll();
+ }
+
+ }
+
+ public void onBeforeShortcutAction(Event e) {
+ getWidgetForPaintable().synchronizeContentToServer();
+ }
+
+ @Override
+ public VRichTextArea getWidgetForPaintable() {
+ return (VRichTextArea) super.getWidgetForPaintable();
+ };
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VRichTextArea.class);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
index acae039e8b..57e257a7cd 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
@@ -14,14 +14,10 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.security.GeneralSecurityException;
-import java.util.Date;
import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
-import java.util.logging.Level;
import java.util.logging.Logger;
import javax.portlet.ActionRequest;
@@ -30,19 +26,16 @@ import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.MimeResponse;
-import javax.portlet.PortalContext;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
-import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
-import javax.portlet.ResourceURL;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
@@ -51,11 +44,13 @@ import com.liferay.portal.kernel.util.PortalClassInvoker;
import com.liferay.portal.kernel.util.PropsUtil;
import com.vaadin.Application;
import com.vaadin.Application.SystemMessages;
-import com.vaadin.terminal.DownloadStream;
+import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.Terminal;
-import com.vaadin.terminal.gwt.client.ApplicationConfiguration;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.ui.Window;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
+import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback;
+import com.vaadin.ui.Root;
/**
* Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0
@@ -71,46 +66,250 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
private static final Logger logger = Logger
.getLogger(AbstractApplicationPortlet.class.getName());
+ private static class WrappedHttpAndPortletRequest extends
+ WrappedPortletRequest {
+
+ public WrappedHttpAndPortletRequest(PortletRequest request,
+ HttpServletRequest originalRequest,
+ DeploymentConfiguration deploymentConfiguration) {
+ super(request, deploymentConfiguration);
+ this.originalRequest = originalRequest;
+ }
+
+ private final HttpServletRequest originalRequest;
+
+ @Override
+ public String getParameter(String name) {
+ String parameter = super.getParameter(name);
+ if (parameter == null) {
+ parameter = originalRequest.getParameter(name);
+ }
+ return parameter;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return originalRequest.getRemoteAddr();
+ }
+
+ @Override
+ public String getHeader(String name) {
+ String header = super.getHeader(name);
+ if (header == null) {
+ header = originalRequest.getHeader(name);
+ }
+ return header;
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ Map<String, String[]> parameterMap = super.getParameterMap();
+ if (parameterMap == null) {
+ parameterMap = originalRequest.getParameterMap();
+ }
+ return parameterMap;
+ }
+ }
+
+ private static class WrappedGateinRequest extends
+ WrappedHttpAndPortletRequest {
+ public WrappedGateinRequest(PortletRequest request,
+ DeploymentConfiguration deploymentConfiguration) {
+ super(request, getOriginalRequest(request), deploymentConfiguration);
+ }
+
+ private static final HttpServletRequest getOriginalRequest(
+ PortletRequest request) {
+ try {
+ Method getRealReq = request.getClass().getMethod(
+ "getRealRequest");
+ HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq
+ .invoke(request);
+ return origRequest;
+ } catch (Exception e) {
+ throw new IllegalStateException("GateIn request not detected",
+ e);
+ }
+ }
+ }
+
+ private static class WrappedLiferayRequest extends
+ WrappedHttpAndPortletRequest {
+
+ public WrappedLiferayRequest(PortletRequest request,
+ DeploymentConfiguration deploymentConfiguration) {
+ super(request, getOriginalRequest(request), deploymentConfiguration);
+ }
+
+ @Override
+ public String getPortalProperty(String name) {
+ return PropsUtil.get(name);
+ }
+
+ private static HttpServletRequest getOriginalRequest(
+ PortletRequest request) {
+ try {
+ // httpRequest = PortalUtil.getHttpServletRequest(request);
+ HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker
+ .invoke("com.liferay.portal.util.PortalUtil",
+ "getHttpServletRequest", request);
+
+ // httpRequest =
+ // PortalUtil.getOriginalServletRequest(httpRequest);
+ httpRequest = (HttpServletRequest) PortalClassInvoker.invoke(
+ "com.liferay.portal.util.PortalUtil",
+ "getOriginalServletRequest", httpRequest);
+ return httpRequest;
+ } catch (Exception e) {
+ throw new IllegalStateException("Liferay request not detected",
+ e);
+ }
+ }
+
+ }
+
+ private static class AbstractApplicationPortletWrapper implements Callback {
+
+ private final AbstractApplicationPortlet portlet;
+
+ public AbstractApplicationPortletWrapper(
+ AbstractApplicationPortlet portlet) {
+ this.portlet = portlet;
+ }
+
+ public void criticalNotification(WrappedRequest request,
+ WrappedResponse response, String cap, String msg,
+ String details, String outOfSyncURL) throws IOException {
+ PortletRequest portletRequest = WrappedPortletRequest.cast(request)
+ .getPortletRequest();
+ PortletResponse portletResponse = ((WrappedPortletResponse) response)
+ .getPortletResponse();
+ portlet.criticalNotification(portletRequest,
+ (MimeResponse) portletResponse, cap, msg, details,
+ outOfSyncURL);
+ }
+ }
+
/**
* This portlet parameter is used to add styles to the main element. E.g
* "height:500px" generates a style="height:500px" to the main element.
*/
public static final String PORTLET_PARAMETER_STYLE = "style";
- private static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme";
+ /**
+ * This portal parameter is used to define the name of the Vaadin theme that
+ * is used for all Vaadin applications in the portal.
+ */
+ public static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme";
// TODO some parts could be shared with AbstractApplicationServlet
// TODO Can we close the application when the portlet is removed? Do we know
// when the portlet is removed?
- // TODO What happens when the portlet window is resized? Do we know when the
- // window is resized?
-
private Properties applicationProperties;
private boolean productionMode = false;
+ private DeploymentConfiguration deploymentConfiguration = new DeploymentConfiguration() {
+ public String getConfiguredWidgetset(WrappedRequest request) {
+
+ String widgetset = getApplicationOrSystemProperty(
+ PARAMETER_WIDGETSET, null);
+
+ if (widgetset == null) {
+ // If no widgetset defined for the application, check the portal
+ // property
+ widgetset = WrappedPortletRequest.cast(request)
+ .getPortalProperty(PORTAL_PARAMETER_VAADIN_WIDGETSET);
+ }
+
+ if (widgetset == null) {
+ // If no widgetset defined for the portal, use the default
+ widgetset = DEFAULT_WIDGETSET;
+ }
+
+ return widgetset;
+ }
+
+ public String getConfiguredTheme(WrappedRequest request) {
+
+ // is the default theme defined by the portal?
+ String themeName = WrappedPortletRequest.cast(request)
+ .getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_THEME);
+
+ if (themeName == null) {
+ // no, using the default theme defined by Vaadin
+ themeName = DEFAULT_THEME_NAME;
+ }
+
+ return themeName;
+ }
+
+ public String getApplicationOrSystemProperty(String propertyName,
+ String defaultValue) {
+ return AbstractApplicationPortlet.this
+ .getApplicationOrSystemProperty(propertyName, defaultValue);
+ }
+
+ public boolean isStandalone(WrappedRequest request) {
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.DeploymentConfiguration#getStaticFileLocation
+ * (com.vaadin.terminal.WrappedRequest)
+ *
+ * Return the URL from where static files, e.g. the widgetset and the
+ * theme, are served. In a standard configuration the VAADIN folder
+ * inside the returned folder is what is used for widgetsets and themes.
+ *
+ * @return The location of static resources (inside which there should
+ * be a VAADIN directory). Does not end with a slash (/).
+ */
+ public String getStaticFileLocation(WrappedRequest request) {
+ String staticFileLocation = WrappedPortletRequest.cast(request)
+ .getPortalProperty(
+ Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH);
+ if (staticFileLocation != null) {
+ // remove trailing slash if any
+ while (staticFileLocation.endsWith(".")) {
+ staticFileLocation = staticFileLocation.substring(0,
+ staticFileLocation.length() - 1);
+ }
+ return staticFileLocation;
+ } else {
+ // default for Liferay
+ return "/html";
+ }
+ }
+ };
+
@Override
public void init(PortletConfig config) throws PortletException {
super.init(config);
- // Stores the application parameters into Properties object
applicationProperties = new Properties();
- for (final Enumeration<String> e = config.getInitParameterNames(); e
+
+ // Read default parameters from the context
+ final PortletContext context = config.getPortletContext();
+ for (final Enumeration<String> e = context.getInitParameterNames(); e
.hasMoreElements();) {
final String name = e.nextElement();
applicationProperties.setProperty(name,
- config.getInitParameter(name));
+ context.getInitParameter(name));
}
- // Overrides with server.xml parameters
- final PortletContext context = config.getPortletContext();
- for (final Enumeration<String> e = context.getInitParameterNames(); e
+ // Override with application settings from portlet.xml
+ for (final Enumeration<String> e = config.getInitParameterNames(); e
.hasMoreElements();) {
final String name = e.nextElement();
applicationProperties.setProperty(name,
- context.getInitParameter(name));
+ config.getInitParameter(name));
}
+
checkProductionMode();
checkCrossSiteProtection();
}
@@ -133,25 +332,21 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
*
* @param request
*/
- private void checkWidgetsetVersion(PortletRequest request) {
- if (!AbstractApplicationServlet.VERSION.equals(getHTTPRequestParameter(
- request, "wsver"))) {
+ private void checkWidgetsetVersion(WrappedRequest request) {
+ if (!AbstractApplicationServlet.VERSION.equals(request
+ .getParameter("wsver"))) {
logger.warning(String.format(WIDGETSET_MISMATCH_INFO,
AbstractApplicationServlet.VERSION,
- getHTTPRequestParameter(request, "wsver")));
+ request.getParameter("wsver")));
}
}
private void checkProductionMode() {
+ // TODO Identical code in AbstractApplicationServlet -> refactor
// Check if the application is in production mode.
- // We are in production mode if Debug=false or productionMode=true
- if (getApplicationOrSystemProperty(SERVLET_PARAMETER_DEBUG, "true")
- .equals("false")) {
- // "Debug=true" is the old way and should no longer be used
- productionMode = true;
- } else if (getApplicationOrSystemProperty(
- SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) {
- // "productionMode=true" is the real way to do it
+ // We are in production mode if productionMode=true
+ if (getApplicationOrSystemProperty(SERVLET_PARAMETER_PRODUCTION_MODE,
+ "false").equals("true")) {
productionMode = true;
}
@@ -241,48 +436,24 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
return defaultValue;
}
- /**
- * Return the URL from where static files, e.g. the widgetset and the theme,
- * are served. In a standard configuration the VAADIN folder inside the
- * returned folder is what is used for widgetsets and themes.
- *
- * @param request
- * @return The location of static resources (inside which there should be a
- * VAADIN directory). Does not end with a slash (/).
- */
- protected String getStaticFilesLocation(PortletRequest request) {
- // TODO allow overriding on portlet level?
- String staticFileLocation = getPortalProperty(
- Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH,
- request.getPortalContext());
- if (staticFileLocation != null) {
- // remove trailing slash if any
- while (staticFileLocation.endsWith(".")) {
- staticFileLocation = staticFileLocation.substring(0,
- staticFileLocation.length() - 1);
- }
- return staticFileLocation;
- } else {
- // default for Liferay
- return "/html";
- }
- }
-
protected enum RequestType {
- FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN;
+ FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS;
}
protected RequestType getRequestType(PortletRequest request) {
if (request instanceof RenderRequest) {
return RequestType.RENDER;
} else if (request instanceof ResourceRequest) {
- if (isUIDLRequest((ResourceRequest) request)) {
+ ResourceRequest resourceRequest = (ResourceRequest) request;
+ if (isUIDLRequest(resourceRequest)) {
return RequestType.UIDL;
- } else if (isFileUploadRequest((ResourceRequest) request)) {
+ } else if (isBrowserDetailsRequeset(resourceRequest)) {
+ return RequestType.BROWSER_DETAILS;
+ } else if (isFileUploadRequest(resourceRequest)) {
return RequestType.FILE_UPLOAD;
- } else if (isApplicationResourceRequest((ResourceRequest) request)) {
+ } else if (isApplicationResourceRequest(resourceRequest)) {
return RequestType.APPLICATION_RESOURCE;
- } else if (isDummyRequest((ResourceRequest) request)) {
+ } else if (isDummyRequest(resourceRequest)) {
return RequestType.DUMMY;
} else {
return RequestType.STATIC_FILE;
@@ -295,6 +466,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
return RequestType.UNKNOWN;
}
+ private boolean isBrowserDetailsRequeset(ResourceRequest request) {
+ return request.getResourceID() != null
+ && request.getResourceID().equals("browserDetails");
+ }
+
private boolean isApplicationResourceRequest(ResourceRequest request) {
return request.getResourceID() != null
&& request.getResourceID().startsWith("APP");
@@ -326,6 +502,27 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
protected void handleRequest(PortletRequest request,
PortletResponse response) throws PortletException, IOException {
+ AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper(
+ this);
+
+ WrappedPortletRequest wrappedRequest;
+
+ String portalInfo = request.getPortalContext().getPortalInfo()
+ .toLowerCase();
+ if (portalInfo.contains("liferay")) {
+ wrappedRequest = new WrappedLiferayRequest(request,
+ getDeploymentConfiguration());
+ } else if (portalInfo.contains("gatein")) {
+ wrappedRequest = new WrappedGateinRequest(request,
+ getDeploymentConfiguration());
+ } else {
+ wrappedRequest = new WrappedPortletRequest(request,
+ getDeploymentConfiguration());
+ }
+
+ WrappedPortletResponse wrappedResponse = new WrappedPortletResponse(
+ response, getDeploymentConfiguration());
+
RequestType requestType = getRequestType(request);
if (requestType == RequestType.UNKNOWN) {
@@ -355,10 +552,12 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// TODO What about PARAM_UNLOADBURST & redirectToApplication??
/* Find out which application this request is related to */
- application = findApplicationInstance(request, requestType);
+ application = findApplicationInstance(wrappedRequest,
+ requestType);
if (application == null) {
return;
}
+ Application.setCurrentApplication(application);
/*
* Get or create an application context and an application
@@ -373,8 +572,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
.getApplicationManager(application);
/* Update browser information from request */
- updateBrowserProperties(applicationContext.getBrowser(),
- request);
+ applicationContext.getBrowser().updateRequestDetails(
+ wrappedRequest);
/*
* Call application requestStart before Application.init() is
@@ -399,20 +598,32 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
/* Notify listeners */
// Finds the window within the application
- Window window = null;
+ Root root = null;
synchronized (application) {
if (application.isRunning()) {
switch (requestType) {
+ case RENDER:
+ try {
+ root = application
+ .getRootForRequest(wrappedRequest);
+ } catch (RootRequiresMoreInformationException e) {
+ // Ignore problem and continue without root
+ }
+ break;
+ case BROWSER_DETAILS:
+ // Should not try to find a root here as the
+ // combined request details might change the root
+ break;
case FILE_UPLOAD:
// no window
break;
case APPLICATION_RESOURCE:
// use main window - should not need any window
- window = application.getMainWindow();
+ // root = application.getRoot();
break;
default:
- window = applicationManager.getApplicationWindow(
- request, this, application, null);
+ root = application
+ .getRootForRequest(wrappedRequest);
}
// if window not found, not a problem - use null
}
@@ -422,37 +633,39 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// starts?
if (request instanceof RenderRequest) {
applicationContext.firePortletRenderRequest(application,
- window, (RenderRequest) request,
+ root, (RenderRequest) request,
(RenderResponse) response);
} else if (request instanceof ActionRequest) {
applicationContext.firePortletActionRequest(application,
- window, (ActionRequest) request,
+ root, (ActionRequest) request,
(ActionResponse) response);
} else if (request instanceof EventRequest) {
applicationContext.firePortletEventRequest(application,
- window, (EventRequest) request,
+ root, (EventRequest) request,
(EventResponse) response);
} else if (request instanceof ResourceRequest) {
applicationContext.firePortletResourceRequest(application,
- window, (ResourceRequest) request,
+ root, (ResourceRequest) request,
(ResourceResponse) response);
}
/* Handle the request */
if (requestType == RequestType.FILE_UPLOAD) {
- applicationManager.handleFileUpload(
- (ResourceRequest) request,
- (ResourceResponse) response);
+ applicationManager.handleFileUpload(wrappedRequest,
+ wrappedResponse);
+ return;
+ } else if (requestType == RequestType.BROWSER_DETAILS) {
+ applicationManager.handleBrowserDetailsRequest(
+ wrappedRequest, wrappedResponse, application);
return;
} else if (requestType == RequestType.UIDL) {
// Handles AJAX UIDL requests
if (isRepaintAll(request)) {
// warn if versions do not match
- checkWidgetsetVersion(request);
+ checkWidgetsetVersion(wrappedRequest);
}
- applicationManager.handleUidlRequest(
- (ResourceRequest) request,
- (ResourceResponse) response, this, window);
+ applicationManager.handleUidlRequest(wrappedRequest,
+ wrappedResponse, portletWrapper, root);
return;
} else {
/*
@@ -463,8 +676,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
return;
}
- handleOtherRequest(request, response, requestType,
- application, window, applicationContext,
+ handleOtherRequest(wrappedRequest, wrappedResponse,
+ requestType, application, applicationContext,
applicationManager);
}
} catch (final SessionExpiredException e) {
@@ -485,16 +698,25 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
.endTransaction(application, request);
}
} finally {
- if (requestStarted) {
- ((PortletRequestListener) application).onRequestEnd(
- request, response);
+ try {
+ if (requestStarted) {
+ ((PortletRequestListener) application)
+ .onRequestEnd(request, response);
+ }
+ } finally {
+ Root.setCurrentRoot(null);
+ Application.setCurrentApplication(null);
}
}
}
}
}
+ private DeploymentConfiguration getDeploymentConfiguration() {
+ return deploymentConfiguration;
+ }
+
private void handleUnknownRequest(PortletRequest request,
PortletResponse response) {
logger.warning("Unknown request type");
@@ -517,37 +739,18 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
* @throws IOException
* @throws MalformedURLException
*/
- private void handleOtherRequest(PortletRequest request,
- PortletResponse response, RequestType requestType,
- Application application, Window window,
+ private void handleOtherRequest(WrappedPortletRequest request,
+ WrappedResponse response, RequestType requestType,
+ Application application,
PortletApplicationContext2 applicationContext,
PortletCommunicationManager applicationManager)
throws PortletException, IOException, MalformedURLException {
- if (window == null) {
- throw new PortletException(ERROR_NO_WINDOW_FOUND);
- }
-
- /*
- * Sets terminal type for the window, if not already set
- */
- if (window.getTerminal() == null) {
- window.setTerminal(applicationContext.getBrowser());
- }
-
- /*
- * Handle parameters
- */
- final Map<String, String[]> parameters = request.getParameterMap();
- if (window != null && parameters != null) {
- window.handleParameters(parameters);
- }
-
- if (requestType == RequestType.APPLICATION_RESOURCE) {
- handleURI(applicationManager, window, (ResourceRequest) request,
- (ResourceResponse) response);
- } else if (requestType == RequestType.RENDER) {
- writeAjaxPage((RenderRequest) request, (RenderResponse) response,
- window, application);
+ if (requestType == RequestType.APPLICATION_RESOURCE
+ || requestType == RequestType.RENDER) {
+ if (!applicationManager.handleApplicationRequest(request, response)) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,
+ "Not found");
+ }
} else if (requestType == RequestType.EVENT) {
// nothing to do, listeners do all the work
} else if (requestType == RequestType.ACTION) {
@@ -558,126 +761,12 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
}
}
- private void updateBrowserProperties(WebBrowser browser,
- PortletRequest request) {
- String userAgent = getHTTPHeader(request, "user-agent");
- browser.updateRequestDetails(request.getLocale(), null,
- request.isSecure(), userAgent);
- if (getHTTPRequestParameter(request, "repaintAll") != null) {
- browser.updateClientSideDetails(
- getHTTPRequestParameter(request, "sw"),
- getHTTPRequestParameter(request, "sh"),
- getHTTPRequestParameter(request, "cw"),
- getHTTPRequestParameter(request, "ch"),
- getHTTPRequestParameter(request, "tzo"),
- getHTTPRequestParameter(request, "rtzo"),
- getHTTPRequestParameter(request, "dstd"),
- getHTTPRequestParameter(request, "dstActive"),
- getHTTPRequestParameter(request, "curdate"),
- getHTTPRequestParameter(request, "td") != null);
- }
- }
-
@Override
public void processEvent(EventRequest request, EventResponse response)
throws PortletException, IOException {
handleRequest(request, response);
}
- private boolean handleURI(PortletCommunicationManager applicationManager,
- Window window, ResourceRequest request, ResourceResponse response)
- throws IOException {
- // Handles the URI
- DownloadStream download = applicationManager.handleURI(window, request,
- response, this);
-
- // A download request
- if (download != null) {
- // Client downloads an resource
- handleDownload(download, request, response);
- return true;
- }
-
- return false;
- }
-
- private void handleDownload(DownloadStream stream, ResourceRequest request,
- ResourceResponse response) throws IOException {
-
- if (stream.getParameter("Location") != null) {
- response.setProperty(ResourceResponse.HTTP_STATUS_CODE,
- Integer.toString(HttpServletResponse.SC_MOVED_TEMPORARILY));
- response.setProperty("Location", stream.getParameter("Location"));
- return;
- }
-
- // Download from given stream
- final InputStream data = stream.getStream();
- if (data != null) {
-
- OutputStream out = null;
- try {
-
- // Sets content type
- response.setContentType(stream.getContentType());
-
- // Sets cache headers
- final long cacheTime = stream.getCacheTime();
- if (cacheTime <= 0) {
- response.setProperty("Cache-Control", "no-cache");
- response.setProperty("Pragma", "no-cache");
- response.setProperty("Expires", "0");
- } else {
- response.setProperty("Cache-Control", "max-age="
- + cacheTime / 1000);
- response.setProperty("Expires",
- "" + System.currentTimeMillis() + cacheTime);
- // Required to apply caching in some Tomcats
- response.setProperty("Pragma", "cache");
- }
-
- // Copy download stream parameters directly
- // to HTTP headers.
- final Iterator<String> i = stream.getParameterNames();
- if (i != null) {
- while (i.hasNext()) {
- final String param = i.next();
- response.setProperty(param, stream.getParameter(param));
- }
- }
-
- // suggest local filename from DownloadStream if
- // Content-Disposition
- // not explicitly set
- String contentDispositionValue = stream
- .getParameter("Content-Disposition");
- if (contentDispositionValue == null) {
- contentDispositionValue = "filename=\""
- + stream.getFileName() + "\"";
- response.setProperty("Content-Disposition",
- contentDispositionValue);
- }
-
- int bufferSize = stream.getBufferSize();
- if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) {
- bufferSize = DEFAULT_BUFFER_SIZE;
- }
- final byte[] buffer = new byte[bufferSize];
- int bytesRead = 0;
-
- out = response.getPortletOutputStream();
-
- while ((bytesRead = data.read(buffer)) > 0) {
- out.write(buffer, 0, bytesRead);
- out.flush();
- }
- } finally {
- AbstractCommunicationManager.tryToCloseStream(data);
- AbstractCommunicationManager.tryToCloseStream(out);
- }
- }
- }
-
private void serveStaticResources(ResourceRequest request,
ResourceResponse response) throws IOException, PortletException {
final String resourceID = request.getResourceID();
@@ -766,7 +855,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
Locale locale = request.getLocale();
application.setLocale(locale);
// No application URL when running inside a portlet
- application.start(null, applicationProperties, context);
+ application.start(null, applicationProperties, context,
+ isProductionMode());
}
}
@@ -780,9 +870,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// Do not send any redirects when running inside a portlet.
}
- private Application findApplicationInstance(PortletRequest request,
- RequestType requestType) throws PortletException,
- SessionExpiredException, MalformedURLException {
+ private Application findApplicationInstance(
+ WrappedPortletRequest wrappedRequest, RequestType requestType)
+ throws PortletException, SessionExpiredException,
+ MalformedURLException {
+ PortletRequest request = wrappedRequest.getPortletRequest();
boolean requestCanCreateApplication = requestCanCreateApplication(
request, requestType);
@@ -797,10 +889,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
* user not specifically requested to close or restart it.
*/
- final boolean restartApplication = (getHTTPRequestParameter(
- request, URL_PARAMETER_RESTART_APPLICATION) != null);
- final boolean closeApplication = (getHTTPRequestParameter(request,
- URL_PARAMETER_CLOSE_APPLICATION) != null);
+ final boolean restartApplication = (wrappedRequest
+ .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null);
+ final boolean closeApplication = (wrappedRequest
+ .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null);
if (restartApplication) {
closeApplication(application, request.getPortletSession(false));
@@ -870,436 +962,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
return null;
}
- /**
- * Returns the URL from which the widgetset is served on the portal.
- *
- * @param widgetset
- * @param request
- * @return
- */
- protected String getWidgetsetURL(String widgetset, PortletRequest request) {
- return getStaticFilesLocation(request) + "/" + WIDGETSET_DIRECTORY_PATH
- + widgetset + "/" + widgetset + ".nocache.js?"
- + new Date().getTime();
- }
-
- /**
- * Returns the theme URI for the named theme on the portal.
- *
- * Note that this is not the only location referring to the theme URI - also
- * e.g. PortletCommunicationManager uses its own way to access the portlet
- * 2.0 theme resources.
- *
- * @param themeName
- * @param request
- * @return
- */
- protected String getThemeURI(String themeName, PortletRequest request) {
- return getStaticFilesLocation(request) + "/" + THEME_DIRECTORY_PATH
- + themeName;
- }
-
- /**
- * Writes the html host page (aka kickstart page) that starts the actual
- * Vaadin application.
- *
- * If one needs to override parts of the portlet HTML contents creation, it
- * is suggested that one overrides one of several submethods including:
- * <ul>
- * <li>
- * {@link #writeAjaxPageHtmlMainDiv(RenderRequest, RenderResponse, BufferedWriter, String)}
- * <li>
- * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)}
- * <li>
- * {@link #writeAjaxPageHtmlVaadinScripts(RenderRequest, RenderResponse, BufferedWriter, Application, String)}
- * </ul>
- *
- * @param request
- * the portlet request.
- * @param response
- * the portlet response to write to.
- * @param window
- * @param application
- * @throws IOException
- * if the writing failed due to input/output error.
- * @throws MalformedURLException
- * if the application is denied access the persistent data store
- * represented by the given URL.
- * @throws PortletException
- */
- protected void writeAjaxPage(RenderRequest request,
- RenderResponse response, Window window, Application application)
- throws IOException, MalformedURLException, PortletException {
-
- response.setContentType("text/html");
- final BufferedWriter page = new BufferedWriter(new OutputStreamWriter(
- response.getPortletOutputStream(), "UTF-8"));
-
- // TODO Currently, we can only load widgetsets and themes from the
- // portal
-
- String themeName = getThemeForWindow(request, window);
-
- writeAjaxPageHtmlVaadinScripts(request, response, page, application,
- themeName);
-
- /*- Add classnames;
- * .v-app
- * .v-app-loading
- * .v-app-<simpleName for app class>
- * .v-theme-<themeName, remove non-alphanum>
- */
- String appClass = "v-app-";
- try {
- appClass += getApplicationClass().getSimpleName();
- } catch (ClassNotFoundException e) {
- appClass += "unknown";
- logger.log(Level.SEVERE, "Could not find application class", e);
- }
- String themeClass = "v-theme-"
- + themeName.replaceAll("[^a-zA-Z0-9]", "");
-
- String classNames = "v-app " + themeClass + " " + appClass;
-
- String style = getApplicationProperty(PORTLET_PARAMETER_STYLE);
- String divStyle = "";
- if (style != null) {
- divStyle = "style=\"" + style + "\"";
- }
-
- writeAjaxPageHtmlMainDiv(request, response, page,
- getApplicationDomId(request), classNames, divStyle);
-
- page.close();
- }
-
- /**
- * Creates and returns a unique ID for the DIV where the application is to
- * be rendered. We need to generate a unique ID because some portals already
- * create a DIV with the portlet's Window ID as the DOM ID.
- *
- * @param request
- * PortletRequest
- * @return the id to use in the DOM
- */
- private String getApplicationDomId(PortletRequest request) {
- return "v-" + request.getWindowID();
- }
-
- /**
- * This method writes the scripts to load the widgetset and the themes as
- * well as define Vaadin configuration parameters on the HTML fragment that
- * starts the actual Vaadin application.
- *
- * @param request
- * @param response
- * @param writer
- * @param application
- * @param themeName
- * @throws IOException
- * @throws PortletException
- */
- protected void writeAjaxPageHtmlVaadinScripts(RenderRequest request,
- RenderResponse response, final BufferedWriter writer,
- Application application, String themeName) throws IOException,
- PortletException {
- String themeURI = getThemeURI(themeName, request);
-
- // fixed base theme to use - all portal pages with Vaadin
- // applications will load this exactly once
- String portalTheme = getPortalProperty(PORTAL_PARAMETER_VAADIN_THEME,
- request.getPortalContext());
-
- writer.write("<script type=\"text/javascript\">\n");
- writer.write("if(!vaadin || !vaadin.vaadinConfigurations) {\n "
- + "if(!vaadin) { var vaadin = {}} \n"
- + "vaadin.vaadinConfigurations = {};\n"
- + "if (!vaadin.themesLoaded) { vaadin.themesLoaded = {}; }\n");
- if (!isProductionMode()) {
- writer.write("vaadin.debug = true;\n");
- }
-
- writeAjaxPageScriptWidgetset(request, response, writer);
-
- Map<String, String> config = getVaadinConfigurationMap(request,
- response, application, themeURI);
- writeAjaxPageScriptConfigurations(request, response, writer, config);
-
- writer.write("</script>\n");
-
- writeAjaxPageHtmlTheme(request, writer, themeName, themeURI,
- portalTheme);
-
- // TODO Warn if widgetset has not been loaded after 15 seconds
- }
-
- /**
- * Writes the script to load the widgetset on the HTML fragment created by
- * the portlet.
- *
- * @param request
- * @param response
- * @param writer
- * @throws IOException
- */
- protected void writeAjaxPageScriptWidgetset(RenderRequest request,
- RenderResponse response, final BufferedWriter writer)
- throws IOException {
- String requestWidgetset = getApplicationOrSystemProperty(
- PARAMETER_WIDGETSET, null);
- String sharedWidgetset = getPortalProperty(
- PORTAL_PARAMETER_VAADIN_WIDGETSET, request.getPortalContext());
-
- String widgetset;
- if (requestWidgetset != null) {
- widgetset = requestWidgetset;
- } else if (sharedWidgetset != null) {
- widgetset = sharedWidgetset;
- } else {
- widgetset = DEFAULT_WIDGETSET;
- }
- String widgetsetURL = getWidgetsetURL(widgetset, request);
- writer.write("document.write('<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" "
- + "style=\"position:absolute;width:0;height:0;border:0;overflow:"
- + "hidden;opacity:0;top:-100px;left:-100px;\" src=\"javascript:false\"></iframe>');\n");
- writer.write("document.write(\"<script language='javascript' src='"
- + widgetsetURL + "'><\\/script>\");\n}\n");
- }
-
- /**
- * Returns the configuration parameters to pass to the client.
- *
- * To add configuration parameters for the client, override, call the super
- * method and then modify the map. Overriding this method may also require
- * client side changes in {@link ApplicationConnection} and
- * {@link ApplicationConfiguration}.
- *
- * Note that this method must escape and quote the values when appropriate.
- *
- * The map returned is typically a {@link LinkedHashMap} to preserve
- * insertion order, but it is not guaranteed to be one.
- *
- * @param request
- * @param response
- * @param application
- * @param themeURI
- * @return modifiable Map from parameter name to its full value
- * @throws PortletException
- */
- protected Map<String, String> getVaadinConfigurationMap(
- RenderRequest request, RenderResponse response,
- Application application, String themeURI) throws PortletException {
- Map<String, String> config = new LinkedHashMap<String, String>();
-
- /*
- * We need this in order to get uploads to work. TODO this is not needed
- * for uploads anymore, check if this is needed for some other things
- */
- PortletURL appUri = response.createActionURL();
- config.put("appUri", "'" + appUri.toString() + "'");
- config.put("usePortletURLs", "true");
- ResourceURL uidlUrlBase = response.createResourceURL();
- uidlUrlBase.setResourceID("UIDL");
- config.put("portletUidlURLBase", "'" + uidlUrlBase.toString() + "'");
- config.put("pathInfo", "''");
- config.put("themeUri", "'" + themeURI + "'");
-
- String versionInfo = "{vaadinVersion:\""
- + AbstractApplicationServlet.VERSION
- + "\",applicationVersion:\"" + application.getVersion() + "\"}";
- config.put("versionInfo", versionInfo);
-
- // Get system messages
- Application.SystemMessages systemMessages = null;
- try {
- systemMessages = getSystemMessages();
- } catch (SystemMessageException e) {
- // failing to get the system messages is always a problem
- throw new PortletException("Failed to obtain system messages!", e);
- }
- if (systemMessages != null) {
- // Write the CommunicationError -message to client
- String caption = systemMessages.getCommunicationErrorCaption();
- if (caption != null) {
- caption = "\"" + caption + "\"";
- }
- String message = systemMessages.getCommunicationErrorMessage();
- if (message != null) {
- message = "\"" + message + "\"";
- }
- String url = systemMessages.getCommunicationErrorURL();
- if (url != null) {
- url = "\"" + url + "\"";
- }
-
- config.put("\"comErrMsg\"", "{" + "\"caption\":" + caption + ","
- + "\"message\" : " + message + "," + "\"url\" : " + url
- + "}");
-
- // Write the AuthenticationError -message to client
- caption = systemMessages.getAuthenticationErrorCaption();
- if (caption != null) {
- caption = "\"" + caption + "\"";
- }
- message = systemMessages.getAuthenticationErrorMessage();
- if (message != null) {
- message = "\"" + message + "\"";
- }
- url = systemMessages.getAuthenticationErrorURL();
- if (url != null) {
- url = "\"" + url + "\"";
- }
-
- config.put("\"authErrMsg\"", "{" + "\"caption\":" + caption + ","
- + "\"message\" : " + message + "," + "\"url\" : " + url
- + "}");
- }
-
- return config;
- }
-
- /**
- * Constructs the Vaadin configuration section for
- * {@link ApplicationConnection} and {@link ApplicationConfiguration}.
- *
- * Typically this method should not be overridden. Instead, modify
- * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)}
- * .
- *
- * @param request
- * @param response
- * @param writer
- * @param config
- * @throws IOException
- * @throws PortletException
- */
- protected void writeAjaxPageScriptConfigurations(RenderRequest request,
- RenderResponse response, final BufferedWriter writer,
- Map<String, String> config) throws IOException, PortletException {
-
- writer.write("vaadin.vaadinConfigurations[\""
- + getApplicationDomId(request) + "\"] = {");
-
- Iterator<String> keyIt = config.keySet().iterator();
- while (keyIt.hasNext()) {
- String key = keyIt.next();
- writer.write(key + ": " + config.get(key));
- if (keyIt.hasNext()) {
- writer.write(", ");
- }
- }
-
- writer.write("};\n");
- }
-
- /**
- * Writes the Vaadin theme loading section of the portlet HTML. Loads both
- * the portal theme and the portlet theme in this order, skipping loading of
- * themes that are already loaded (matched by name).
- *
- * @param request
- * @param writer
- * @param themeName
- * @param themeURI
- * @param portalTheme
- * @throws IOException
- */
- protected void writeAjaxPageHtmlTheme(RenderRequest request,
- final BufferedWriter writer, String themeName, String themeURI,
- String portalTheme) throws IOException {
- writer.write("<script type=\"text/javascript\">\n");
-
- if (portalTheme == null) {
- portalTheme = DEFAULT_THEME_NAME;
- }
-
- writer.write("if(!vaadin.themesLoaded['" + portalTheme + "']) {\n");
- writer.write("var defaultStylesheet = document.createElement('link');\n");
- writer.write("defaultStylesheet.setAttribute('rel', 'stylesheet');\n");
- writer.write("defaultStylesheet.setAttribute('type', 'text/css');\n");
- writer.write("defaultStylesheet.setAttribute('href', '"
- + getThemeURI(portalTheme, request) + "/styles.css');\n");
- writer.write("document.getElementsByTagName('head')[0].appendChild(defaultStylesheet);\n");
- writer.write("vaadin.themesLoaded['" + portalTheme + "'] = true;\n}\n");
-
- if (!portalTheme.equals(themeName)) {
- writer.write("if(!vaadin.themesLoaded['" + themeName + "']) {\n");
- writer.write("var stylesheet = document.createElement('link');\n");
- writer.write("stylesheet.setAttribute('rel', 'stylesheet');\n");
- writer.write("stylesheet.setAttribute('type', 'text/css');\n");
- writer.write("stylesheet.setAttribute('href', '" + themeURI
- + "/styles.css');\n");
- writer.write("document.getElementsByTagName('head')[0].appendChild(stylesheet);\n");
- writer.write("vaadin.themesLoaded['" + themeName
- + "'] = true;\n}\n");
- }
-
- writer.write("</script>\n");
- }
-
- /**
- * Method to write the div element into which that actual Vaadin application
- * is rendered.
- * <p>
- * Override this method if you want to add some custom html around around
- * the div element into which the actual Vaadin application will be
- * rendered.
- *
- * @param request
- * @param response
- * @param writer
- * @param id
- * @param classNames
- * @param divStyle
- * @throws IOException
- */
- protected void writeAjaxPageHtmlMainDiv(RenderRequest request,
- RenderResponse response, final BufferedWriter writer, String id,
- String classNames, String divStyle) throws IOException {
- writer.write("<div id=\"" + id + "\" class=\"" + classNames + "\" "
- + divStyle + ">");
- writer.write("<div class=\"v-app-loading\"></div>");
- writer.write("</div>\n");
- writer.write("<noscript>" + getNoScriptMessage() + "</noscript>");
- }
-
- /**
- * Returns a message printed for browsers without scripting support or if
- * browsers scripting support is disabled.
- */
- protected String getNoScriptMessage() {
- return "You have to enable javascript in your browser to use an application built with Vaadin.";
- }
-
- /**
- * Returns the theme for given request/window
- *
- * @param request
- * @param window
- * @return
- */
- protected String getThemeForWindow(PortletRequest request, Window window) {
- // Finds theme name
- String themeName;
-
- // theme defined for the window?
- themeName = window.getTheme();
-
- if (themeName == null) {
- // no, is the default theme defined by the portal?
- themeName = getPortalProperty(
- Constants.PORTAL_PARAMETER_VAADIN_THEME,
- request.getPortalContext());
- }
-
- if (themeName == null) {
- // no, using the default theme defined by Vaadin
- themeName = DEFAULT_THEME_NAME;
- }
-
- return themeName;
- }
-
protected abstract Class<? extends Application> getApplicationClass()
throws ClassNotFoundException;
@@ -1307,6 +969,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
throws PortletException {
try {
final Application application = getApplicationClass().newInstance();
+ application.setRootPreserved(true);
return application;
} catch (final IllegalAccessException e) {
throw new PortletException("getNewApplication failed", e);
@@ -1454,162 +1117,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
}
/**
- * Returns a portal configuration property.
- *
- * Liferay is handled separately as
- * {@link PortalContext#getProperty(String)} does not return portal
- * properties from e.g. portal-ext.properties .
- *
- * @param name
- * @param context
- * @return
- */
- protected static String getPortalProperty(String name, PortalContext context) {
- boolean isLifeRay = context.getPortalInfo().toLowerCase()
- .contains("liferay");
-
- // TODO test on non-LifeRay platforms
-
- String value;
- if (isLifeRay) {
- value = getLifeRayPortalProperty(name);
- } else {
- value = context.getProperty(name);
- }
-
- return value;
- }
-
- private static String getLifeRayPortalProperty(String name) {
- String value;
- try {
- value = PropsUtil.get(name);
- } catch (Exception e) {
- value = null;
- }
- return value;
- }
-
- /**
- * Try to get an HTTP header value from a request using portal specific
- * APIs.
- *
- * @param name
- * HTTP header name
- * @return the value of the header (empty string if defined without a value,
- * null if the parameter is not present or retrieving it failed)
- */
- private static String getHTTPHeader(PortletRequest request, String name) {
- String value = null;
- String portalInfo = request.getPortalContext().getPortalInfo()
- .toLowerCase();
- if (portalInfo.contains("liferay")) {
- value = getLiferayHTTPHeader(request, name);
- } else if (portalInfo.contains("gatein")) {
- value = getGateInHTTPHeader(request, name);
- }
- return value;
- }
-
- /**
- * Try to get the value of a HTTP request parameter from a portlet request
- * using portal specific APIs. It is not possible to get the HTTP request
- * parameters using the official Portlet 2.0 API.
- *
- * @param name
- * HTTP request parameter name
- * @return the value of the parameter (empty string if parameter defined
- * without a value, null if the parameter is not present or
- * retrieving it failed)
- */
- private static String getHTTPRequestParameter(PortletRequest request,
- String name) {
- String value = request.getParameter(name);
- if (value == null) {
- String portalInfo = request.getPortalContext().getPortalInfo()
- .toLowerCase();
- if (portalInfo.contains("liferay")) {
- value = getLiferayHTTPRequestParameter(request, name);
- } else if (portalInfo.contains("gatein")) {
- value = getGateInHTTPRequestParameter(request, name);
- }
- }
- return value;
- }
-
- private static String getGateInHTTPRequestParameter(PortletRequest request,
- String name) {
- String value = null;
- try {
- Method getRealReq = request.getClass().getMethod("getRealRequest");
- HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq
- .invoke(request);
- value = origRequest.getParameter(name);
- } catch (Exception e) {
- // do nothing - not on GateIn simple-portal
- }
- return value;
- }
-
- private static String getLiferayHTTPRequestParameter(
- PortletRequest request, String name) {
- try {
- // httpRequest = PortalUtil.getHttpServletRequest(request);
- HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker
- .invoke("com.liferay.portal.util.PortalUtil",
- "getHttpServletRequest", request);
-
- // httpRequest =
- // PortalUtil.getOriginalServletRequest(httpRequest);
- httpRequest = (HttpServletRequest) PortalClassInvoker.invoke(
- "com.liferay.portal.util.PortalUtil",
- "getOriginalServletRequest", httpRequest);
- if (httpRequest != null) {
- return httpRequest.getParameter(name);
- }
- } catch (Exception e) {
- // ignore and return null - unable to get the original request
- }
- return null;
- }
-
- private static String getGateInHTTPHeader(PortletRequest request,
- String name) {
- String value = null;
- try {
- Method getRealReq = request.getClass().getMethod("getRealRequest");
- HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq
- .invoke(request);
- value = origRequest.getHeader(name);
- } catch (Exception e) {
- // do nothing - not on GateIn simple-portal
- }
- return value;
- }
-
- private static String getLiferayHTTPHeader(PortletRequest request,
- String name) {
- try {
- // httpRequest = PortalUtil.getHttpServletRequest(request);
- HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker
- .invoke("com.liferay.portal.util.PortalUtil",
- "getHttpServletRequest", request);
-
- // httpRequest =
- // PortalUtil.getOriginalServletRequest(httpRequest);
- httpRequest = (HttpServletRequest) PortalClassInvoker.invoke(
- "com.liferay.portal.util.PortalUtil",
- "getOriginalServletRequest", httpRequest);
- if (httpRequest != null) {
- return httpRequest.getHeader(name);
- }
- } catch (Exception e) {
- // ignore and return null - unable to get the original request
- }
- return null;
- }
-
- /**
*
* Gets the application context for a PortletSession. If no context is
* currently stored in a session a new context is created and stored in the
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index 3957c84a71..b28cb361b0 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -18,12 +18,10 @@ import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
-import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -38,13 +36,14 @@ import javax.servlet.http.HttpSession;
import com.vaadin.Application;
import com.vaadin.Application.SystemMessages;
-import com.vaadin.terminal.DownloadStream;
-import com.vaadin.terminal.ParameterHandler;
+import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.Terminal;
import com.vaadin.terminal.ThemeResource;
-import com.vaadin.terminal.URIHandler;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.ui.Window;
+import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback;
+import com.vaadin.ui.Root;
/**
* Abstract implementation of the ApplicationServlet which handles all
@@ -64,6 +63,25 @@ import com.vaadin.ui.Window;
public abstract class AbstractApplicationServlet extends HttpServlet implements
Constants {
+ private static class AbstractApplicationServletWrapper implements Callback {
+
+ private final AbstractApplicationServlet servlet;
+
+ public AbstractApplicationServletWrapper(
+ AbstractApplicationServlet servlet) {
+ this.servlet = servlet;
+ }
+
+ public void criticalNotification(WrappedRequest request,
+ WrappedResponse response, String cap, String msg,
+ String details, String outOfSyncURL) throws IOException {
+ servlet.criticalNotification(
+ WrappedHttpServletRequest.cast(request),
+ ((WrappedHttpServletResponse) response), cap, msg, details,
+ outOfSyncURL);
+ }
+ }
+
// TODO Move some (all?) of the constants to a separate interface (shared
// with portlet)
@@ -115,67 +133,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
}
- /**
- * If the attribute is present in the request, a html fragment will be
- * written instead of a whole page.
- *
- * It is set to "true" by the {@link ApplicationPortlet} (Portlet 1.0) and
- * read by {@link AbstractApplicationServlet}.
- */
- public static final String REQUEST_FRAGMENT = ApplicationServlet.class
- .getName() + ".fragment";
- /**
- * This request attribute forces widgetsets to be loaded from under the
- * specified base path; e.g shared widgetset for all portlets in a portal.
- *
- * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on
- * {@link Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH} and read by
- * {@link AbstractApplicationServlet}.
- */
- public static final String REQUEST_VAADIN_STATIC_FILE_PATH = ApplicationServlet.class
- .getName() + ".widgetsetPath";
- /**
- * This request attribute forces widgetset used; e.g for portlets that can
- * not have different widgetsets.
- *
- * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on
- * {@link ApplicationPortlet.PORTLET_PARAMETER_WIDGETSET} and read by
- * {@link AbstractApplicationServlet}.
- */
- public static final String REQUEST_WIDGETSET = ApplicationServlet.class
- .getName() + ".widgetset";
- /**
- * This request attribute indicates the shared widgetset (e.g. portal-wide
- * default widgetset).
- *
- * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on
- * {@link Constants.PORTAL_PARAMETER_VAADIN_WIDGETSET} and read by
- * {@link AbstractApplicationServlet}.
- */
- public static final String REQUEST_SHARED_WIDGETSET = ApplicationServlet.class
- .getName() + ".sharedWidgetset";
- /**
- * If set, do not load the default theme but assume that loading it is
- * handled e.g. by ApplicationPortlet.
- *
- * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on
- * {@link Constants.PORTAL_PARAMETER_VAADIN_THEME} and read by
- * {@link AbstractApplicationServlet}.
- */
- public static final String REQUEST_DEFAULT_THEME = ApplicationServlet.class
- .getName() + ".defaultThemeUri";
- /**
- * This request attribute is used to add styles to the main element. E.g
- * "height:500px" generates a style="height:500px" to the main element,
- * useful from some embedding situations (e.g portlet include.)
- *
- * It is typically set by the {@link ApplicationPortlet} (Portlet 1.0) based
- * on {@link ApplicationPortlet.PORTLET_PARAMETER_STYLE} and read by
- * {@link AbstractApplicationServlet}.
- */
- public static final String REQUEST_APPSTYLE = ApplicationServlet.class
- .getName() + ".style";
-
private Properties applicationProperties;
private boolean productionMode = false;
@@ -183,6 +140,37 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
private final String resourcePath = null;
private int resourceCacheTime = 3600;
+
+ private DeploymentConfiguration deploymentConfiguration = new DeploymentConfiguration() {
+ public String getStaticFileLocation(WrappedRequest request) {
+ HttpServletRequest servletRequest = WrappedHttpServletRequest
+ .cast(request);
+ return AbstractApplicationServlet.this
+ .getStaticFilesLocation(servletRequest);
+ }
+
+ public String getConfiguredWidgetset(WrappedRequest request) {
+ return getApplicationOrSystemProperty(
+ AbstractApplicationServlet.PARAMETER_WIDGETSET,
+ AbstractApplicationServlet.DEFAULT_WIDGETSET);
+ }
+
+ public String getConfiguredTheme(WrappedRequest request) {
+ // Use the default
+ return AbstractApplicationServlet.getDefaultTheme();
+ }
+
+ public String getApplicationOrSystemProperty(String propertyName,
+ String defaultValue) {
+ return AbstractApplicationServlet.this
+ .getApplicationOrSystemProperty(propertyName, defaultValue);
+ }
+
+ public boolean isStandalone(WrappedRequest request) {
+ return true;
+ }
+ };
+
static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/";
/**
@@ -201,17 +189,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
public void init(javax.servlet.ServletConfig servletConfig)
throws javax.servlet.ServletException {
super.init(servletConfig);
-
- // Stores the application parameters into Properties object
applicationProperties = new Properties();
- for (final Enumeration<String> e = servletConfig
- .getInitParameterNames(); e.hasMoreElements();) {
- final String name = e.nextElement();
- applicationProperties.setProperty(name,
- servletConfig.getInitParameter(name));
- }
- // Overrides with server.xml parameters
+ // Read default parameters from server.xml
final ServletContext context = servletConfig.getServletContext();
for (final Enumeration<String> e = context.getInitParameterNames(); e
.hasMoreElements();) {
@@ -219,6 +199,15 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
applicationProperties.setProperty(name,
context.getInitParameter(name));
}
+
+ // Override with application config from web.xml
+ for (final Enumeration<String> e = servletConfig
+ .getInitParameterNames(); e.hasMoreElements();) {
+ final String name = e.nextElement();
+ applicationProperties.setProperty(name,
+ servletConfig.getInitParameter(name));
+ }
+
checkProductionMode();
checkCrossSiteProtection();
checkResourceCacheTime();
@@ -251,14 +240,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
private void checkProductionMode() {
// Check if the application is in production mode.
- // We are in production mode if Debug=false or productionMode=true
- if (getApplicationOrSystemProperty(SERVLET_PARAMETER_DEBUG, "true")
- .equals("false")) {
- // "Debug=true" is the old way and should no longer be used
- productionMode = true;
- } else if (getApplicationOrSystemProperty(
- SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) {
- // "productionMode=true" is the real way to do it
+ // We are in production mode if productionMode=true
+ if (getApplicationOrSystemProperty(SERVLET_PARAMETER_PRODUCTION_MODE,
+ "false").equals("true")) {
productionMode = true;
}
@@ -341,7 +325,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* the Default to be used.
* @return String value or default if not found
*/
- private String getApplicationOrSystemProperty(String parameterName,
+ String getApplicationOrSystemProperty(String parameterName,
String defaultValue) {
String val = null;
@@ -397,10 +381,17 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* @throws IOException
* if the request for the TRACE cannot be handled.
*/
- @SuppressWarnings("unchecked")
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
+ service(createWrappedRequest(request), createWrappedResponse(response));
+ }
+
+ private void service(WrappedHttpServletRequest request,
+ WrappedHttpServletResponse response) throws ServletException,
+ IOException {
+ AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper(
+ this);
RequestType requestType = getRequestType(request);
if (!ensureCookiesEnabled(requestType, request, response)) {
@@ -445,6 +436,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
if (application == null) {
return;
}
+ Application.setCurrentApplication(application);
/*
* Get or create a WebApplicationContext and an ApplicationManager
@@ -456,7 +448,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
.getApplicationManager(application, this);
/* Update browser information from the request */
- updateBrowserProperties(webApplicationContext.getBrowser(), request);
+ webApplicationContext.getBrowser().updateRequestDetails(request);
/*
* Call application requestStart before Application.init() is called
@@ -468,7 +460,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
requestStarted = true;
}
- // Start the newly created application
+ // Start the application if it's newly created
startApplication(request, application, webApplicationContext);
/*
@@ -484,10 +476,16 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return;
} else if (requestType == RequestType.UIDL) {
// Handles AJAX UIDL requests
- Window window = applicationManager.getApplicationWindow(
- request, this, application, null);
- applicationManager.handleUidlRequest(request, response, this,
- window);
+ Root root = application.getRootForRequest(request);
+ if (root == null) {
+ throw new ServletException(ERROR_NO_WINDOW_FOUND);
+ }
+ applicationManager.handleUidlRequest(request, response,
+ servletWrapper, root);
+ return;
+ } else if (requestType == RequestType.BROWSER_DETAILS) {
+ applicationManager.handleBrowserDetailsRequest(request,
+ response, application);
return;
}
@@ -498,34 +496,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return;
}
- // Finds the window within the application
- Window window = getApplicationWindow(request, applicationManager,
- application);
- if (window == null) {
- throw new ServletException(ERROR_NO_WINDOW_FOUND);
- }
-
- // Sets terminal type for the window, if not already set
- if (window.getTerminal() == null) {
- window.setTerminal(webApplicationContext.getBrowser());
- }
-
- // Handle parameters
- final Map<String, String[]> parameters = request.getParameterMap();
- if (window != null && parameters != null) {
- window.handleParameters(parameters);
- }
-
- /*
- * Call the URI handlers and if this turns out to be a download
- * request, send the file to the client
- */
- if (handleURI(applicationManager, window, request, response)) {
+ if (applicationManager.handleApplicationRequest(request, response)) {
return;
}
-
- // Send initial AJAX page that kickstarts a Vaadin application
- writeAjaxPage(request, response, window, application);
+ // TODO Should return 404 error here and not do anything more
} catch (final SessionExpiredException e) {
// Session has expired, notify user
@@ -544,9 +518,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
} finally {
- if (requestStarted) {
- ((HttpServletRequestListener) application).onRequestEnd(
- request, response);
+ try {
+ if (requestStarted) {
+ ((HttpServletRequestListener) application)
+ .onRequestEnd(request, response);
+ }
+ } finally {
+ Root.setCurrentRoot(null);
+ Application.setCurrentApplication(null);
}
}
@@ -554,6 +533,36 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
}
+ private WrappedHttpServletResponse createWrappedResponse(
+ HttpServletResponse response) {
+ WrappedHttpServletResponse wrappedResponse = new WrappedHttpServletResponse(
+ response, getDeploymentConfiguration());
+ return wrappedResponse;
+ }
+
+ /**
+ * Create a wrapped request for a http servlet request. This method can be
+ * overridden if the wrapped request should have special properties.
+ *
+ * @param request
+ * the original http servlet request
+ * @return a wrapped request for the original request
+ */
+ protected WrappedHttpServletRequest createWrappedRequest(
+ HttpServletRequest request) {
+ return new WrappedHttpServletRequest(request,
+ getDeploymentConfiguration());
+ }
+
+ /**
+ * Gets a the deployment configuration for this servlet.
+ *
+ * @return the deployment configuration
+ */
+ protected DeploymentConfiguration getDeploymentConfiguration() {
+ return deploymentConfiguration;
+ }
+
/**
* Check that cookie support is enabled in the browser. Only checks UIDL
* requests.
@@ -587,23 +596,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return true;
}
- private void updateBrowserProperties(WebBrowser browser,
- HttpServletRequest request) {
- // request based details updated always
- browser.updateRequestDetails(request.getLocale(),
- request.getRemoteAddr(), request.isSecure(),
- request.getHeader("user-agent"));
- if (request.getParameter("repaintAll") != null) {
- browser.updateClientSideDetails(request.getParameter("sw"),
- request.getParameter("sh"), request.getParameter("cw"),
- request.getParameter("ch"), request.getParameter("tzo"),
- request.getParameter("rtzo"), request.getParameter("dstd"),
- request.getParameter("dston"),
- request.getParameter("curdate"),
- request.getParameter("td") != null);
- }
- }
-
protected ClassLoader getClassLoader() throws ServletException {
// Gets custom class loader
final String classLoaderName = getApplicationOrSystemProperty(
@@ -812,7 +804,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/*
* UIDL request contains valid repaintAll=1 event, the user probably
* wants to initiate a new application through a custom index.html
- * without using writeAjaxPage.
+ * without using the bootstrap page.
*/
return true;
@@ -858,101 +850,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- * Handles the requested URI. An application can add handlers to do special
- * processing, when a certain URI is requested. The handlers are invoked
- * before any windows URIs are processed and if a DownloadStream is returned
- * it is sent to the client.
- *
- * @param stream
- * the download stream.
- *
- * @param request
- * the HTTP request instance.
- * @param response
- * the HTTP response to write to.
- * @throws IOException
- *
- * @see com.vaadin.terminal.URIHandler
- */
- private void handleDownload(DownloadStream stream,
- HttpServletRequest request, HttpServletResponse response)
- throws IOException {
-
- if (stream.getParameter("Location") != null) {
- response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
- response.addHeader("Location", stream.getParameter("Location"));
- return;
- }
-
- // Download from given stream
- final InputStream data = stream.getStream();
- if (data != null) {
-
- OutputStream out = null;
- try {
- // Sets content type
- response.setContentType(stream.getContentType());
-
- // Sets cache headers
- final long cacheTime = stream.getCacheTime();
- if (cacheTime <= 0) {
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- response.setDateHeader("Expires", 0);
- } else {
- response.setHeader("Cache-Control", "max-age=" + cacheTime
- / 1000);
- response.setDateHeader("Expires",
- System.currentTimeMillis() + cacheTime);
- response.setHeader("Pragma", "cache"); // Required to apply
- // caching in some
- // Tomcats
- }
-
- // Copy download stream parameters directly
- // to HTTP headers.
- final Iterator<String> i = stream.getParameterNames();
- if (i != null) {
- while (i.hasNext()) {
- final String param = i.next();
- response.setHeader(param, stream.getParameter(param));
- }
- }
-
- // suggest local filename from DownloadStream if
- // Content-Disposition
- // not explicitly set
- String contentDispositionValue = stream
- .getParameter("Content-Disposition");
- if (contentDispositionValue == null) {
- contentDispositionValue = "filename=\""
- + stream.getFileName() + "\"";
- response.setHeader("Content-Disposition",
- contentDispositionValue);
- }
-
- int bufferSize = stream.getBufferSize();
- if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) {
- bufferSize = DEFAULT_BUFFER_SIZE;
- }
- final byte[] buffer = new byte[bufferSize];
- int bytesRead = 0;
-
- out = response.getOutputStream();
-
- while ((bytesRead = data.read(buffer)) > 0) {
- out.write(buffer, 0, bytesRead);
- out.flush();
- }
- } finally {
- AbstractCommunicationManager.tryToCloseStream(out);
- AbstractCommunicationManager.tryToCloseStream(data);
- }
- }
-
- }
-
- /**
* Creates a new application and registers it into WebApplicationContext
* (aka session). This is not meant to be overridden. Override
* getNewApplication to create the application instance in a custom way.
@@ -996,42 +893,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- * Returns the theme for given request/window
- *
- * @param request
- * @param window
- * @return
- */
- private String getThemeForWindow(HttpServletRequest request, Window window) {
- // Finds theme name
- String themeName;
-
- if (request.getParameter(URL_PARAMETER_THEME) != null) {
- themeName = request.getParameter(URL_PARAMETER_THEME);
- } else {
- themeName = window.getTheme();
- }
-
- if (themeName == null) {
- // no explicit theme for window defined
- if (request.getAttribute(REQUEST_DEFAULT_THEME) != null) {
- // the default theme is defined in request (by portal)
- themeName = (String) request
- .getAttribute(REQUEST_DEFAULT_THEME);
- } else {
- // using the default theme defined by Vaadin
- themeName = getDefaultTheme();
- }
- }
-
- // XSS preventation, theme names shouldn't contain special chars anyway.
- // The servlet denies them via url parameter.
- themeName = stripSpecialChars(themeName);
-
- return themeName;
- }
-
- /**
* A helper method to strip away characters that might somehow be used for
* XSS attacs. Leaves at least alphanumeric characters intact. Also removes
* eg. ( and ), so values should be safe in javascript too.
@@ -1064,34 +925,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return DEFAULT_THEME_NAME;
}
- /**
- * Calls URI handlers for the request. If an URI handler returns a
- * DownloadStream the stream is passed to the client for downloading.
- *
- * @param applicationManager
- * @param window
- * @param request
- * @param response
- * @return true if an DownloadStream was sent to the client, false otherwise
- * @throws IOException
- */
- protected boolean handleURI(CommunicationManager applicationManager,
- Window window, HttpServletRequest request,
- HttpServletResponse response) throws IOException {
- // Handles the URI
- DownloadStream download = applicationManager.handleURI(window, request,
- response, this);
-
- // A download request
- if (download != null) {
- // Client downloads an resource
- handleDownload(download, request, response);
- return true;
- }
-
- return false;
- }
-
void handleServiceSessionExpired(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
@@ -1200,7 +1033,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
Locale locale = request.getLocale();
application.setLocale(locale);
application.start(applicationUrl, applicationProperties,
- webApplicationContext);
+ webApplicationContext, isProductionMode());
}
}
@@ -1435,12 +1268,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
protected enum RequestType {
- FILE_UPLOAD, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE;
+ FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE;
}
protected RequestType getRequestType(HttpServletRequest request) {
if (isFileUploadRequest(request)) {
return RequestType.FILE_UPLOAD;
+ } else if (isBrowserDetailsRequest(request)) {
+ return RequestType.BROWSER_DETAILS;
} else if (isUIDLRequest(request)) {
return RequestType.UIDL;
} else if (isStaticResourceRequest(request)) {
@@ -1454,6 +1289,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
+ private static boolean isBrowserDetailsRequest(HttpServletRequest request) {
+ return "POST".equals(request.getMethod())
+ && request.getParameter("browserDetails") != null;
+ }
+
private boolean isApplicationRequest(HttpServletRequest request) {
String path = getRequestPathInfo(request);
if (path != null && path.startsWith("/APP/")) {
@@ -1520,13 +1360,25 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* @return
*/
protected SystemMessages getSystemMessages() {
+ Class<? extends Application> appCls = null;
try {
- Class<? extends Application> appCls = getApplicationClass();
- Method m = appCls.getMethod("getSystemMessages", (Class[]) null);
- return (Application.SystemMessages) m.invoke(null, (Object[]) null);
+ appCls = getApplicationClass();
} catch (ClassNotFoundException e) {
- // This should never happen
+ // Previous comment claimed that this should never happen
throw new SystemMessageException(e);
+ }
+ return getSystemMessages(appCls);
+ }
+
+ public static SystemMessages getSystemMessages(
+ Class<? extends Application> appCls) {
+ try {
+ if (appCls != null) {
+ Method m = appCls
+ .getMethod("getSystemMessages", (Class[]) null);
+ return (Application.SystemMessages) m.invoke(null,
+ (Object[]) null);
+ }
} catch (SecurityException e) {
throw new SystemMessageException(
"Application.getSystemMessage() should be static public", e);
@@ -1562,15 +1414,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
*/
protected String getStaticFilesLocation(HttpServletRequest request) {
- // request may have an attribute explicitly telling location (portal
- // case)
- String staticFileLocation = (String) request
- .getAttribute(REQUEST_VAADIN_STATIC_FILE_PATH);
- if (staticFileLocation != null) {
- // TODO remove trailing slash if any?
- return staticFileLocation;
- }
-
return getWebApplicationsStaticFileLocation(request);
}
@@ -1653,473 +1496,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- * This method writes the html host page (aka kickstart page) that starts
- * the actual Vaadin application.
- * <p>
- * If one needs to override parts of the host page, it is suggested that one
- * overrides on of several submethods which are called by this method:
- * <ul>
- * <li> {@link #setAjaxPageHeaders(HttpServletResponse)}
- * <li>
- * {@link #writeAjaxPageHtmlHeadStart(BufferedWriter, HttpServletRequest)}
- * <li>
- * {@link #writeAjaxPageHtmlHeader(BufferedWriter, String, String, HttpServletRequest)}
- * <li>
- * {@link #writeAjaxPageHtmlBodyStart(BufferedWriter, HttpServletRequest)}
- * <li>
- * {@link #writeAjaxPageHtmlVaadinScripts(Window, String, Application, BufferedWriter, String, String, String, HttpServletRequest)}
- * <li>
- * {@link #writeAjaxPageHtmlMainDiv(BufferedWriter, String, String, String, HttpServletRequest)}
- * <li> {@link #writeAjaxPageHtmlBodyEnd(BufferedWriter)}
- * </ul>
- *
- * @param request
- * the HTTP request.
- * @param response
- * the HTTP response to write to.
- * @param out
- * @param unhandledParameters
- * @param window
- * @param terminalType
- * @param theme
- * @throws IOException
- * if the writing failed due to input/output error.
- * @throws MalformedURLException
- * if the application is denied access the persistent data store
- * represented by the given URL.
- */
- protected void writeAjaxPage(HttpServletRequest request,
- HttpServletResponse response, Window window, Application application)
- throws IOException, MalformedURLException, ServletException {
-
- // e.g portlets only want a html fragment
- boolean fragment = (request.getAttribute(REQUEST_FRAGMENT) != null);
- if (fragment) {
- // if this is a fragment request, the actual application is put to
- // request so ApplicationPortlet can save it for a later use
- request.setAttribute(Application.class.getName(), application);
- }
-
- final BufferedWriter page = new BufferedWriter(new OutputStreamWriter(
- response.getOutputStream(), "UTF-8"));
-
- String title = ((window.getCaption() == null) ? "Vaadin 6" : window
- .getCaption());
-
- /* Fetch relative url to application */
- // don't use server and port in uri. It may cause problems with some
- // virtual server configurations which lose the server name
- String appUrl = getApplicationUrl(request).getPath();
- if (appUrl.endsWith("/")) {
- appUrl = appUrl.substring(0, appUrl.length() - 1);
- }
-
- String themeName = getThemeForWindow(request, window);
-
- String themeUri = getThemeUri(themeName, request);
-
- if (!fragment) {
- setAjaxPageHeaders(response);
- writeAjaxPageHtmlHeadStart(page, request);
- writeAjaxPageHtmlHeader(page, title, themeUri, request);
- writeAjaxPageHtmlBodyStart(page, request);
- }
-
- String appId = appUrl;
- if ("".equals(appUrl)) {
- appId = "ROOT";
- }
- appId = appId.replaceAll("[^a-zA-Z0-9]", "");
- // Add hashCode to the end, so that it is still (sort of) predictable,
- // but indicates that it should not be used in CSS and such:
- int hashCode = appId.hashCode();
- if (hashCode < 0) {
- hashCode = -hashCode;
- }
- appId = appId + "-" + hashCode;
-
- writeAjaxPageHtmlVaadinScripts(window, themeName, application, page,
- appUrl, themeUri, appId, request);
-
- /*- Add classnames;
- * .v-app
- * .v-app-loading
- * .v-app-<simpleName for app class>
- * .v-theme-<themeName, remove non-alphanum>
- */
-
- String appClass = "v-app-" + getApplicationCSSClassName();
-
- String themeClass = "";
- if (themeName != null) {
- themeClass = "v-theme-" + themeName.replaceAll("[^a-zA-Z0-9]", "");
- } else {
- themeClass = "v-theme-"
- + getDefaultTheme().replaceAll("[^a-zA-Z0-9]", "");
- }
-
- String classNames = "v-app " + themeClass + " " + appClass;
-
- String divStyle = null;
- if (request.getAttribute(REQUEST_APPSTYLE) != null) {
- divStyle = "style=\"" + request.getAttribute(REQUEST_APPSTYLE)
- + "\"";
- }
-
- writeAjaxPageHtmlMainDiv(page, appId, classNames, divStyle, request);
-
- if (!fragment) {
- page.write("</body>\n</html>\n");
- }
-
- page.close();
-
- }
-
- /**
- * Returns the application class identifier for use in the application CSS
- * class name in the root DIV. The application CSS class name is of form
- * "v-app-"+getApplicationCSSClassName().
- *
- * This method should normally not be overridden.
- *
- * @return The CSS class name to use in combination with "v-app-".
- */
- protected String getApplicationCSSClassName() {
- try {
- return getApplicationClass().getSimpleName();
- } catch (ClassNotFoundException e) {
- logger.log(Level.WARNING, "getApplicationCSSClassName failed", e);
- return "unknown";
- }
- }
-
- /**
- * Get the URI for the application theme.
- *
- * A portal-wide default theme is fetched from the portal shared resource
- * directory (if any), other themes from the portlet.
- *
- * @param themeName
- * @param request
- * @return
- */
- private String getThemeUri(String themeName, HttpServletRequest request) {
- final String staticFilePath;
- if (themeName.equals(request.getAttribute(REQUEST_DEFAULT_THEME))) {
- // our window theme is the portal wide default theme, make it load
- // from portals directory is defined
- staticFilePath = getStaticFilesLocation(request);
- } else {
- /*
- * theme is a custom theme, which is not necessarily located in
- * portals VAADIN directory. Let the default servlet conf decide
- * (omitting request parameter) the location. Note that theme can
- * still be placed to portal directory with servlet parameter.
- */
- staticFilePath = getWebApplicationsStaticFileLocation(request);
- }
- return staticFilePath + "/" + THEME_DIRECTORY_PATH + themeName;
- }
-
- /**
- * Method to write the div element into which that actual Vaadin application
- * is rendered.
- * <p>
- * Override this method if you want to add some custom html around around
- * the div element into which the actual Vaadin application will be
- * rendered.
- *
- * @param page
- * @param appId
- * @param classNames
- * @param divStyle
- * @param request
- * @throws IOException
- */
- protected void writeAjaxPageHtmlMainDiv(final BufferedWriter page,
- String appId, String classNames, String divStyle,
- HttpServletRequest request) throws IOException {
- page.write("<div id=\"" + appId + "\" class=\"" + classNames + "\" "
- + (divStyle != null ? divStyle : "") + ">");
- page.write("<div class=\"v-app-loading\"></div>");
- page.write("</div>\n");
- page.write("<noscript>" + getNoScriptMessage() + "</noscript>");
- }
-
- /**
- * Method to write the script part of the page which loads needed Vaadin
- * scripts and themes.
- * <p>
- * Override this method if you want to add some custom html around scripts.
- *
- * @param window
- * @param themeName
- * @param application
- * @param page
- * @param appUrl
- * @param themeUri
- * @param appId
- * @param request
- * @throws ServletException
- * @throws IOException
- */
- protected void writeAjaxPageHtmlVaadinScripts(Window window,
- String themeName, Application application,
- final BufferedWriter page, String appUrl, String themeUri,
- String appId, HttpServletRequest request) throws ServletException,
- IOException {
-
- // request widgetset takes precedence (e.g portlet include)
- String requestWidgetset = (String) request
- .getAttribute(REQUEST_WIDGETSET);
- String sharedWidgetset = (String) request
- .getAttribute(REQUEST_SHARED_WIDGETSET);
- if (requestWidgetset == null && sharedWidgetset == null) {
- // Use the value from configuration or DEFAULT_WIDGETSET.
- // If no shared widgetset is specified, the default widgetset is
- // assumed to be in the servlet/portlet itself.
- requestWidgetset = getApplicationOrSystemProperty(
- PARAMETER_WIDGETSET, DEFAULT_WIDGETSET);
- }
-
- String widgetset;
- String widgetsetBasePath;
- if (requestWidgetset != null) {
- widgetset = requestWidgetset;
- widgetsetBasePath = getWebApplicationsStaticFileLocation(request);
- } else {
- widgetset = sharedWidgetset;
- widgetsetBasePath = getStaticFilesLocation(request);
- }
-
- widgetset = stripSpecialChars(widgetset);
-
- final String widgetsetFilePath = widgetsetBasePath + "/"
- + WIDGETSET_DIRECTORY_PATH + widgetset + "/" + widgetset
- + ".nocache.js?" + new Date().getTime();
-
- // Get system messages
- Application.SystemMessages systemMessages = null;
- try {
- systemMessages = getSystemMessages();
- } catch (SystemMessageException e) {
- // failing to get the system messages is always a problem
- throw new ServletException("CommunicationError!", e);
- }
-
- page.write("<script type=\"text/javascript\">\n");
- page.write("//<![CDATA[\n");
- page.write("if(!vaadin || !vaadin.vaadinConfigurations) {\n "
- + "if(!vaadin) { var vaadin = {}} \n"
- + "vaadin.vaadinConfigurations = {};\n"
- + "if (!vaadin.themesLoaded) { vaadin.themesLoaded = {}; }\n");
- if (!isProductionMode()) {
- page.write("vaadin.debug = true;\n");
- }
- page.write("document.write('<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" "
- + "style=\"position:absolute;width:0;height:0;border:0;overflow:"
- + "hidden;\" src=\"javascript:false\"></iframe>');\n");
- page.write("document.write(\"<script language='javascript' src='"
- + widgetsetFilePath + "'><\\/script>\");\n}\n");
-
- page.write("vaadin.vaadinConfigurations[\"" + appId + "\"] = {");
- page.write("appUri:'" + appUrl + "', ");
-
- if (window != application.getMainWindow()) {
- page.write("windowName: \""
- + JsonPaintTarget.escapeJSON(window.getName()) + "\", ");
- }
- if (isStandalone()) {
- page.write("standalone: true, ");
- }
- page.write("themeUri:");
- page.write(themeUri != null ? "\"" + themeUri + "\"" : "null");
- page.write(", versionInfo : {vaadinVersion:\"");
- page.write(VERSION);
- page.write("\",applicationVersion:\"");
- page.write(JsonPaintTarget.escapeJSON(application.getVersion()));
- page.write("\"}");
- if (systemMessages != null) {
- // Write the CommunicationError -message to client
- String caption = systemMessages.getCommunicationErrorCaption();
- if (caption != null) {
- caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\"";
- }
- String message = systemMessages.getCommunicationErrorMessage();
- if (message != null) {
- message = "\"" + JsonPaintTarget.escapeJSON(message) + "\"";
- }
- String url = systemMessages.getCommunicationErrorURL();
- if (url != null) {
- url = "\"" + JsonPaintTarget.escapeJSON(url) + "\"";
- }
-
- page.write(",\"comErrMsg\": {" + "\"caption\":" + caption + ","
- + "\"message\" : " + message + "," + "\"url\" : " + url
- + "}");
-
- // Write the AuthenticationError -message to client
- caption = systemMessages.getAuthenticationErrorCaption();
- if (caption != null) {
- caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\"";
- }
- message = systemMessages.getAuthenticationErrorMessage();
- if (message != null) {
- message = "\"" + JsonPaintTarget.escapeJSON(message) + "\"";
- }
- url = systemMessages.getAuthenticationErrorURL();
- if (url != null) {
- url = "\"" + JsonPaintTarget.escapeJSON(url) + "\"";
- }
-
- page.write(",\"authErrMsg\": {" + "\"caption\":" + caption + ","
- + "\"message\" : " + message + "," + "\"url\" : " + url
- + "}");
- }
- page.write("};\n//]]>\n</script>\n");
-
- if (themeName != null) {
- // Custom theme's stylesheet, load only once, in different
- // script
- // tag to be dominate styles injected by widget
- // set
- page.write("<script type=\"text/javascript\">\n");
- page.write("//<![CDATA[\n");
- page.write("if(!vaadin.themesLoaded['" + themeName + "']) {\n");
- page.write("var stylesheet = document.createElement('link');\n");
- page.write("stylesheet.setAttribute('rel', 'stylesheet');\n");
- page.write("stylesheet.setAttribute('type', 'text/css');\n");
- page.write("stylesheet.setAttribute('href', '" + themeUri
- + "/styles.css');\n");
- page.write("document.getElementsByTagName('head')[0].appendChild(stylesheet);\n");
- page.write("vaadin.themesLoaded['" + themeName + "'] = true;\n}\n");
- page.write("//]]>\n</script>\n");
- }
-
- // Warn if the widgetset has not been loaded after 15 seconds on
- // inactivity
- page.write("<script type=\"text/javascript\">\n");
- page.write("//<![CDATA[\n");
- page.write("setTimeout('if (typeof " + widgetset.replace('.', '_')
- + " == \"undefined\") {alert(\"Failed to load the widgetset: "
- + widgetsetFilePath + "\")};',15000);\n" + "//]]>\n</script>\n");
- }
-
- /**
- * @return true if the served application is considered to be the only or
- * main content of the host page. E.g. various embedding solutions
- * should override this to false.
- */
- protected boolean isStandalone() {
- return true;
- }
-
- /**
- *
- * Method to open the body tag of the html kickstart page.
- * <p>
- * This method is responsible for closing the head tag and opening the body
- * tag.
- * <p>
- * Override this method if you want to add some custom html to the page.
- *
- * @param page
- * @param request
- * @throws IOException
- */
- protected void writeAjaxPageHtmlBodyStart(final BufferedWriter page,
- final HttpServletRequest request) throws IOException {
- page.write("\n</head>\n<body scroll=\"auto\" class=\""
- + ApplicationConnection.GENERATED_BODY_CLASSNAME + "\">\n");
- }
-
- /**
- * Method to write the contents of head element in html kickstart page.
- * <p>
- * Override this method if you want to add some custom html to the header of
- * the page.
- *
- * @param page
- * @param title
- * @param themeUri
- * @param request
- * @throws IOException
- */
- protected void writeAjaxPageHtmlHeader(final BufferedWriter page,
- String title, String themeUri, final HttpServletRequest request)
- throws IOException {
- page.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n");
-
- WebBrowser browser = getApplicationContext(request.getSession())
- .getBrowser();
- if (browser.isIE()) {
- // Chrome frame in all versions of IE (only if Chrome frame is
- // installed)
- page.write("<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\"/>\n");
- }
-
- page.write("<style type=\"text/css\">"
- + "html, body {height:100%;margin:0;}</style>");
-
- // Add favicon links
- page.write("<link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\" href=\""
- + themeUri + "/favicon.ico\" />");
- page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\""
- + themeUri + "/favicon.ico\" />");
-
- page.write("<title>" + safeEscapeForHtml(title) + "</title>");
- }
-
- /**
- * Method to write the beginning of the html page.
- * <p>
- * This method is responsible for writing appropriate doc type declarations
- * and to open html and head tags.
- * <p>
- * Override this method if you want to add some custom html to the very
- * beginning of the page.
- *
- * @param page
- * @param request
- * @throws IOException
- */
- protected void writeAjaxPageHtmlHeadStart(final BufferedWriter page,
- final HttpServletRequest request) throws IOException {
- // write html header
- page.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD "
- + "XHTML 1.0 Transitional//EN\" "
- + "\"http://www.w3.org/TR/xhtml1/"
- + "DTD/xhtml1-transitional.dtd\">\n");
-
- page.write("<html xmlns=\"http://www.w3.org/1999/xhtml\""
- + ">\n<head>\n");
- }
-
- /**
- * Method to set http request headers for the Vaadin kickstart page.
- * <p>
- * Override this method if you need to customize http headers of the page.
- *
- * @param response
- */
- protected void setAjaxPageHeaders(HttpServletResponse response) {
- // Window renders are not cacheable
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- response.setDateHeader("Expires", 0);
- response.setContentType("text/html; charset=UTF-8");
- }
-
- /**
- * Returns a message printed for browsers without scripting support or if
- * browsers scripting support is disabled.
- */
- protected String getNoScriptMessage() {
- return "You have to enable javascript in your browser to use an application built with Vaadin.";
- }
-
- /**
* Gets the current application URL from request.
*
* @param request
@@ -2247,52 +1623,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- * Gets the existing application or create a new one. Get a window within an
- * application based on the requested URI.
- *
- * @param request
- * the HTTP Request.
- * @param application
- * the Application to query for window.
- * @return Window matching the given URI or null if not found.
- * @throws ServletException
- * if an exception has occurred that interferes with the
- * servlet's normal operation.
- */
- protected Window getApplicationWindow(HttpServletRequest request,
- CommunicationManager applicationManager, Application application)
- throws ServletException {
-
- // Finds the window where the request is handled
- Window assumedWindow = null;
- String path = getRequestPathInfo(request);
-
- // Main window as the URI is empty
- if (!(path == null || path.length() == 0 || path.equals("/"))) {
- if (path.startsWith("/APP/")) {
- // Use main window for application resources
- return application.getMainWindow();
- }
- String windowName = null;
- if (path.charAt(0) == '/') {
- path = path.substring(1);
- }
- final int index = path.indexOf('/');
- if (index < 0) {
- windowName = path;
- path = "";
- } else {
- windowName = path.substring(0, index);
- }
- assumedWindow = application.getWindow(windowName);
-
- }
-
- return applicationManager.getApplicationWindow(request, this,
- application, assumedWindow);
- }
-
- /**
* Returns the path info; note that this _can_ be different than
* request.getPathInfo(). Examples where this might be useful:
* <ul>
@@ -2362,75 +1692,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return WebApplicationContext.getApplicationContext(session);
}
- /**
- * Implementation of ParameterHandler.ErrorEvent interface.
- */
- public class ParameterHandlerErrorImpl implements
- ParameterHandler.ErrorEvent, Serializable {
-
- private ParameterHandler owner;
-
- private Throwable throwable;
-
- /**
- * Gets the contained throwable.
- *
- * @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable()
- */
- public Throwable getThrowable() {
- return throwable;
- }
-
- /**
- * Gets the source ParameterHandler.
- *
- * @see com.vaadin.terminal.ParameterHandler.ErrorEvent#getParameterHandler()
- */
- public ParameterHandler getParameterHandler() {
- return owner;
- }
-
- }
-
- /**
- * Implementation of URIHandler.ErrorEvent interface.
- */
- public class URIHandlerErrorImpl implements URIHandler.ErrorEvent,
- Serializable {
-
- private final URIHandler owner;
-
- private final Throwable throwable;
-
- /**
- *
- * @param owner
- * @param throwable
- */
- private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) {
- this.owner = owner;
- this.throwable = throwable;
- }
-
- /**
- * Gets the contained throwable.
- *
- * @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable()
- */
- public Throwable getThrowable() {
- return throwable;
- }
-
- /**
- * Gets the source URIHandler.
- *
- * @see com.vaadin.terminal.URIHandler.ErrorEvent#getURIHandler()
- */
- public URIHandler getURIHandler() {
- return owner;
- }
- }
-
public class RequestError implements Terminal.ErrorEvent, Serializable {
private final Throwable throwable;
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index e96f2d2b56..86f2c7a2de 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -14,9 +14,9 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Serializable;
+import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.URL;
import java.security.GeneralSecurityException;
import java.text.CharacterIterator;
import java.text.DateFormat;
@@ -42,32 +42,32 @@ import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.portlet.PortletRequest;
-import javax.portlet.PortletResponse;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
import com.vaadin.Application;
import com.vaadin.Application.SystemMessages;
-import com.vaadin.terminal.ApplicationResource;
-import com.vaadin.terminal.DownloadStream;
+import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.external.json.JSONException;
+import com.vaadin.external.json.JSONObject;
+import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Paintable;
import com.vaadin.terminal.Paintable.RepaintRequestEvent;
+import com.vaadin.terminal.RequestHandler;
import com.vaadin.terminal.StreamVariable;
import com.vaadin.terminal.StreamVariable.StreamingEndEvent;
import com.vaadin.terminal.StreamVariable.StreamingErrorEvent;
import com.vaadin.terminal.Terminal.ErrorEvent;
import com.vaadin.terminal.Terminal.ErrorListener;
-import com.vaadin.terminal.URIHandler;
import com.vaadin.terminal.VariableOwner;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.server.BootstrapHandler.BootstrapContext;
import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.Component;
-import com.vaadin.ui.Window;
+import com.vaadin.ui.Root;
/**
* This is a common base class for the server-side implementations of the
@@ -78,7 +78,7 @@ import com.vaadin.ui.Window;
* A server side component sends its state to the client in a paint request (see
* {@link Paintable} and {@link PaintTarget} on the server side). The client
* widget receives these paint requests as calls to
- * {@link com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL()}. The client
+ * {@link com.vaadin.terminal.gwt.client.VPaintableWidget#updateFromUIDL()}. The client
* component communicates back to the server by sending a list of variable
* changes (see {@link ApplicationConnection#updateVariable()} and
* {@link VariableOwner#changeVariables(Object, Map)}).
@@ -94,177 +94,20 @@ public abstract class AbstractCommunicationManager implements
private static final Logger logger = Logger
.getLogger(AbstractCommunicationManager.class.getName());
- /**
- * Generic interface of a (HTTP or Portlet) request to the application.
- *
- * This is a wrapper interface that allows
- * {@link AbstractCommunicationManager} to use a unified API.
- *
- * @see javax.servlet.ServletRequest
- * @see javax.portlet.PortletRequest
- *
- * @author peholmst
- */
- public interface Request {
-
- /**
- * Gets a {@link Session} wrapper implementation representing the
- * session for which this request was sent.
- *
- * Multiple Vaadin applications can be associated with a single session.
- *
- * @return Session
- */
- public Session getSession();
-
- /**
- * Are the applications in this session running in a portlet or directly
- * as servlets.
- *
- * @return true if in a portlet
- */
- public boolean isRunningInPortlet();
-
- /**
- * Get the named HTTP or portlet request parameter.
- *
- * @see javax.servlet.ServletRequest#getParameter(String)
- * @see javax.portlet.PortletRequest#getParameter(String)
- *
- * @param name
- * @return
- */
- public String getParameter(String name);
-
- /**
- * Returns the length of the request content that can be read from the
- * input stream returned by {@link #getInputStream()}.
- *
- * @return content length in bytes
- */
- public int getContentLength();
-
- /**
- * Returns an input stream from which the request content can be read.
- * The request content length can be obtained with
- * {@link #getContentLength()} without reading the full stream contents.
- *
- * @return
- * @throws IOException
- */
- public InputStream getInputStream() throws IOException;
-
- /**
- * Returns the request identifier that identifies the target Vaadin
- * window for the request.
- *
- * @return String identifier for the request target window
- */
- public String getRequestID();
-
- /**
- * @see javax.servlet.ServletRequest#getAttribute(String)
- * @see javax.portlet.PortletRequest#getAttribute(String)
- */
- public Object getAttribute(String name);
-
- /**
- * @see javax.servlet.ServletRequest#setAttribute(String, Object)
- * @see javax.portlet.PortletRequest#setAttribute(String, Object)
- */
- public void setAttribute(String name, Object value);
-
- /**
- * Gets the underlying request object. The request is typically either a
- * {@link ServletRequest} or a {@link PortletRequest}.
- *
- * @return wrapped request object
- */
- public Object getWrappedRequest();
-
- }
-
- /**
- * Generic interface of a (HTTP or Portlet) response from the application.
- *
- * This is a wrapper interface that allows
- * {@link AbstractCommunicationManager} to use a unified API.
- *
- * @see javax.servlet.ServletResponse
- * @see javax.portlet.PortletResponse
- *
- * @author peholmst
- */
- public interface Response {
-
- /**
- * Gets the output stream to which the response can be written.
- *
- * @return
- * @throws IOException
- */
- public OutputStream getOutputStream() throws IOException;
-
- /**
- * Sets the MIME content type for the response to be communicated to the
- * browser.
- *
- * @param type
- */
- public void setContentType(String type);
-
- /**
- * Gets the wrapped response object, usually a class implementing either
- * {@link ServletResponse} or {@link PortletResponse}.
- *
- * @return wrapped request object
- */
- public Object getWrappedResponse();
+ private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler();
- }
+ private static final RequestHandler UNSUPPORTED_BROWSER_HANDLER = new UnsupportedBrowserHandler();
/**
- * Generic wrapper interface for a (HTTP or Portlet) session.
- *
- * Several applications can be associated with a single session.
- *
* TODO Document me!
*
- * @see javax.servlet.http.HttpSession
- * @see javax.portlet.PortletSession
- *
* @author peholmst
*/
- protected interface Session {
-
- public boolean isNew();
-
- public Object getAttribute(String name);
-
- public void setAttribute(String name, Object o);
-
- public int getMaxInactiveInterval();
-
- public Object getWrappedSession();
-
- }
-
- /**
- * TODO Document me!
- *
- * @author peholmst
- */
- public interface Callback {
-
- public void criticalNotification(Request request, Response response,
- String cap, String msg, String details, String outOfSyncURL)
- throws IOException;
-
- public String getRequestPathInfo(Request request);
-
- public InputStream getThemeResourceAsStream(String themeName,
- String resource) throws IOException;
+ public interface Callback extends Serializable {
+ public void criticalNotification(WrappedRequest request,
+ WrappedResponse response, String cap, String msg,
+ String details, String outOfSyncURL) throws IOException;
}
static class UploadInterruptedException extends Exception {
@@ -306,7 +149,7 @@ public abstract class AbstractCommunicationManager implements
public static final char VAR_ESCAPE_CHARACTER = '\u001b';
- private final HashMap<String, OpenWindowCache> currentlyOpenWindowsInClient = new HashMap<String, OpenWindowCache>();
+ private final HashMap<Integer, OpenWindowCache> currentlyOpenWindowsInClient = new HashMap<Integer, OpenWindowCache>();
private static final int MAX_BUFFER_SIZE = 64 * 1024;
@@ -325,10 +168,6 @@ public abstract class AbstractCommunicationManager implements
private final Application application;
- // Note that this is only accessed from synchronized block and
- // thus should be thread-safe.
- private String closingWindowName = null;
-
private List<String> locales;
private int pendingLocalesIndex;
@@ -341,8 +180,6 @@ public abstract class AbstractCommunicationManager implements
private int maxInactiveInterval;
- private static int nextUnusedWindowSuffix = 1;
-
/**
* TODO New constructor - document me!
*
@@ -350,6 +187,9 @@ public abstract class AbstractCommunicationManager implements
*/
public AbstractCommunicationManager(Application application) {
this.application = application;
+ application.addRequestHandler(getBootstrapHandler());
+ application.addRequestHandler(APP_RESOURCE_HANDLER);
+ application.addRequestHandler(UNSUPPORTED_BROWSER_HANDLER);
requireLocale(application.getLocale().toString());
}
@@ -390,8 +230,8 @@ public abstract class AbstractCommunicationManager implements
* @param boundary
* @throws IOException
*/
- protected void doHandleSimpleMultipartFileUpload(Request request,
- Response response, StreamVariable streamVariable,
+ protected void doHandleSimpleMultipartFileUpload(WrappedRequest request,
+ WrappedResponse response, StreamVariable streamVariable,
String variableName, VariableOwner owner, String boundary)
throws IOException {
// multipart parsing, supports only one file for request, but that is
@@ -489,9 +329,10 @@ public abstract class AbstractCommunicationManager implements
* @param contentLength
* @throws IOException
*/
- protected void doHandleXhrFilePost(Request request, Response response,
- StreamVariable streamVariable, String variableName,
- VariableOwner owner, int contentLength) throws IOException {
+ protected void doHandleXhrFilePost(WrappedRequest request,
+ WrappedResponse response, StreamVariable streamVariable,
+ String variableName, VariableOwner owner, int contentLength)
+ throws IOException {
// These are unknown in filexhr ATM, maybe add to Accept header that
// is accessible in portlets
@@ -628,17 +469,6 @@ public abstract class AbstractCommunicationManager implements
}
}
- static void tryToCloseStream(InputStream in) {
- try {
- // try to close output stream (e.g. file handle)
- if (in != null) {
- in.close();
- }
- } catch (IOException e1) {
- // NOP
- }
- }
-
/**
* Removes any possible path information from the filename and returns the
* filename. Separators / and \\ are used.
@@ -661,8 +491,8 @@ public abstract class AbstractCommunicationManager implements
* @param response
* @throws IOException
*/
- protected void sendUploadResponse(Request request, Response response)
- throws IOException {
+ protected void sendUploadResponse(WrappedRequest request,
+ WrappedResponse response) throws IOException {
response.setContentType("text/html");
final OutputStream out = response.getOutputStream();
final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
@@ -676,7 +506,7 @@ public abstract class AbstractCommunicationManager implements
* Internally process a UIDL request from the client.
*
* This method calls
- * {@link #handleVariables(Request, Response, Callback, Application, Window)}
+ * {@link #handleVariables(WrappedRequest, WrappedResponse, Callback, Application, Root)}
* to process any changes to variables by the client and then repaints
* affected components using {@link #paintAfterVariableChanges()}.
*
@@ -690,18 +520,18 @@ public abstract class AbstractCommunicationManager implements
* @param request
* @param response
* @param callback
- * @param window
+ * @param root
* target window for the UIDL request, can be null if target not
* found
* @throws IOException
* @throws InvalidUIDLSecurityKeyException
*/
- protected void doHandleUidlRequest(Request request, Response response,
- Callback callback, Window window) throws IOException,
- InvalidUIDLSecurityKeyException {
+ public void handleUidlRequest(WrappedRequest request,
+ WrappedResponse response, Callback callback, Root root)
+ throws IOException, InvalidUIDLSecurityKeyException {
requestThemeName = request.getParameter("theme");
- maxInactiveInterval = request.getSession().getMaxInactiveInterval();
+ maxInactiveInterval = request.getSessionMaxInactiveInterval();
// repaint requested or session has timed out and new one is created
boolean repaintAll;
final OutputStream out;
@@ -734,11 +564,10 @@ public abstract class AbstractCommunicationManager implements
// Finds the window within the application
if (application.isRunning()) {
// Returns if no window found
- if (window == null) {
+ if (root == null) {
// This should not happen, no windows exists but
// application is still open.
- logger.warning("Could not get window for application with request ID "
- + request.getRequestID());
+ logger.warning("Could not get root for application");
return;
}
} else {
@@ -748,8 +577,7 @@ public abstract class AbstractCommunicationManager implements
}
// Change all variables based on request parameters
- if (!handleVariables(request, response, callback, application,
- window)) {
+ if (!handleVariables(request, response, callback, application, root)) {
// var inconsistency; the client is probably out-of-sync
SystemMessages ci = null;
@@ -780,12 +608,8 @@ public abstract class AbstractCommunicationManager implements
}
paintAfterVariableChanges(request, response, callback, repaintAll,
- outWriter, window, analyzeLayouts);
+ outWriter, root, analyzeLayouts);
- if (closingWindowName != null) {
- currentlyOpenWindowsInClient.remove(closingWindowName);
- closingWindowName = null;
- }
}
outWriter.close();
@@ -864,13 +688,13 @@ public abstract class AbstractCommunicationManager implements
* @throws PaintException
* @throws IOException
*/
- private void paintAfterVariableChanges(Request request, Response response,
- Callback callback, boolean repaintAll, final PrintWriter outWriter,
- Window window, boolean analyzeLayouts) throws PaintException,
- IOException {
+ private void paintAfterVariableChanges(WrappedRequest request,
+ WrappedResponse response, Callback callback, boolean repaintAll,
+ final PrintWriter outWriter, Root root, boolean analyzeLayouts)
+ throws PaintException, IOException {
if (repaintAll) {
- makeAllPaintablesDirty(window);
+ makeAllPaintablesDirty(root);
}
// Removes application if it has stopped during variable changes
@@ -886,44 +710,54 @@ public abstract class AbstractCommunicationManager implements
.getAttribute(WRITE_SECURITY_TOKEN_FLAG);
if (writeSecurityTokenFlag != null) {
- String seckey = (String) request.getSession().getAttribute(
- ApplicationConnection.UIDL_SECURITY_TOKEN_ID);
- if (seckey == null) {
- seckey = UUID.randomUUID().toString();
- request.getSession().setAttribute(
- ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey);
- }
- outWriter.print("\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID
- + "\":\"");
- outWriter.print(seckey);
- outWriter.print("\",");
+ outWriter.print(getSecurityKeyUIDL(request));
}
- // If the browser-window has been closed - we do not need to paint it at
- // all
- if (window.getName().equals(closingWindowName)) {
- outWriter.print("\"changes\":[]");
- } else {
- // re-get window - may have been changed
- Window newWindow = doGetApplicationWindow(request, callback,
- application, window);
- if (newWindow != window) {
- window = newWindow;
- repaintAll = true;
- }
-
- writeUidlResponce(callback, repaintAll, outWriter, window,
- analyzeLayouts);
+ writeUidlResponce(repaintAll, outWriter, root, analyzeLayouts);
- }
closeJsonMessage(outWriter);
outWriter.close();
}
- public void writeUidlResponce(Callback callback, boolean repaintAll,
- final PrintWriter outWriter, Window window, boolean analyzeLayouts)
+ /**
+ * Gets the security key (and generates one if needed) as UIDL.
+ *
+ * @param request
+ * @return the security key UIDL or "" if the feature is turned off
+ */
+ public String getSecurityKeyUIDL(WrappedRequest request) {
+ final String seckey = getSecurityKey(request);
+ if (seckey != null) {
+ return "\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID
+ + "\":\"" + seckey + "\",";
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Gets the security key (and generates one if needed).
+ *
+ * @param request
+ * @return the security key
+ */
+ protected String getSecurityKey(WrappedRequest request) {
+ String seckey = null;
+ seckey = (String) request
+ .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID);
+ if (seckey == null) {
+ seckey = UUID.randomUUID().toString();
+ request.setSessionAttribute(
+ ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey);
+ }
+
+ return seckey;
+ }
+
+ public void writeUidlResponce(boolean repaintAll,
+ final PrintWriter outWriter, Root root, boolean analyzeLayouts)
throws PaintException {
outWriter.print("\"changes\":[");
@@ -933,17 +767,18 @@ public abstract class AbstractCommunicationManager implements
JsonPaintTarget paintTarget = new JsonPaintTarget(this, outWriter,
!repaintAll);
- OpenWindowCache windowCache = currentlyOpenWindowsInClient.get(window
- .getName());
+ OpenWindowCache windowCache = currentlyOpenWindowsInClient.get(Integer
+ .valueOf(root.getRootId()));
if (windowCache == null) {
windowCache = new OpenWindowCache();
- currentlyOpenWindowsInClient.put(window.getName(), windowCache);
+ currentlyOpenWindowsInClient.put(Integer.valueOf(root.getRootId()),
+ windowCache);
}
// Paints components
if (repaintAll) {
paintables = new ArrayList<Paintable>();
- paintables.add(window);
+ paintables.add(root);
// Reset sent locales
locales = null;
@@ -973,7 +808,7 @@ public abstract class AbstractCommunicationManager implements
dirtyPaintables.remove(p);
}
}
- paintables = getDirtyVisibleComponents(window);
+ paintables = getDirtyVisibleComponents(root);
}
if (paintables != null) {
@@ -1008,13 +843,13 @@ public abstract class AbstractCommunicationManager implements
.hasNext();) {
final Paintable p = i.next();
- // TODO CLEAN
- if (p instanceof Window) {
- final Window w = (Window) p;
- if (w.getTerminal() == null) {
- w.setTerminal(application.getMainWindow().getTerminal());
- }
- }
+ // // TODO CLEAN
+ // if (p instanceof Root) {
+ // final Root r = (Root) p;
+ // if (r.getTerminal() == null) {
+ // r.setTerminal(application.getRoot().getTerminal());
+ // }
+ // }
/*
* This does not seem to happen in tk5, but remember this case:
* else if (p instanceof Component) { if (((Component)
@@ -1038,20 +873,20 @@ public abstract class AbstractCommunicationManager implements
paintablePainted(p);
if (analyzeLayouts) {
- Window w = (Window) p;
+ Root w = (Root) p;
invalidComponentRelativeSizes = ComponentSizeValidator
.validateComponentRelativeSizes(w.getContent(),
null, null);
- // Also check any existing subwindows
- if (w.getChildWindows() != null) {
- for (Window subWindow : w.getChildWindows()) {
- invalidComponentRelativeSizes = ComponentSizeValidator
- .validateComponentRelativeSizes(
- subWindow.getContent(),
- invalidComponentRelativeSizes, null);
- }
- }
+ // // Also check any existing subwindows
+ // if (w.getChildWindows() != null) {
+ // for (Window subWindow : w.getChildWindows()) {
+ // invalidComponentRelativeSizes = ComponentSizeValidator
+ // .validateComponentRelativeSizes(
+ // subWindow.getContent(),
+ // invalidComponentRelativeSizes, null);
+ // }
+ // }
}
}
}
@@ -1140,8 +975,7 @@ public abstract class AbstractCommunicationManager implements
final String resource = (String) i.next();
InputStream is = null;
try {
- is = callback.getThemeResourceAsStream(getTheme(window),
- resource);
+ is = getThemeResourceAsStream(root, getTheme(root), resource);
} catch (final Exception e) {
// FIXME: Handle exception
logger.log(Level.FINER, "Failed to get theme resource stream.",
@@ -1207,12 +1041,15 @@ public abstract class AbstractCommunicationManager implements
}
}
+ protected abstract InputStream getThemeResourceAsStream(Root root,
+ String themeName, String resource);
+
private int getTimeoutInterval() {
return maxInactiveInterval;
}
- private String getTheme(Window window) {
- String themeName = window.getTheme();
+ private String getTheme(Root root) {
+ String themeName = root.getApplication().getThemeForRoot(root);
String requestThemeName = getRequestTheme();
if (requestThemeName != null) {
@@ -1228,19 +1065,19 @@ public abstract class AbstractCommunicationManager implements
return requestThemeName;
}
- public void makeAllPaintablesDirty(Window window) {
+ public void makeAllPaintablesDirty(Root root) {
// If repaint is requested, clean all ids in this root window
for (final Iterator<String> it = idPaintableMap.keySet().iterator(); it
.hasNext();) {
final Component c = (Component) idPaintableMap.get(it.next());
- if (isChildOf(window, c)) {
+ if (isChildOf(root, c)) {
it.remove();
paintableIdMap.remove(c);
}
}
// clean WindowCache
OpenWindowCache openWindowCache = currentlyOpenWindowsInClient
- .get(window.getName());
+ .get(Integer.valueOf(root.getRootId()));
if (openWindowCache != null) {
openWindowCache.clear();
}
@@ -1257,6 +1094,18 @@ public abstract class AbstractCommunicationManager implements
}
/**
+ * Returns false if the cross site request forgery protection is turned off.
+ *
+ * @param application
+ * @return false if the XSRF is turned off, true otherwise
+ */
+ public boolean isXSRFEnabled(Application application) {
+ return !"true"
+ .equals(application
+ .getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION));
+ }
+
+ /**
* TODO document
*
* If this method returns false, something was submitted that we did not
@@ -1265,9 +1114,10 @@ public abstract class AbstractCommunicationManager implements
*
* @return true if successful, false if there was an inconsistency
*/
- private boolean handleVariables(Request request, Response response,
- Callback callback, Application application2, Window window)
- throws IOException, InvalidUIDLSecurityKeyException {
+ private boolean handleVariables(WrappedRequest request,
+ WrappedResponse response, Callback callback,
+ Application application2, Root root) throws IOException,
+ InvalidUIDLSecurityKeyException {
boolean success = true;
String changes = getRequestPayload(request);
@@ -1279,9 +1129,7 @@ public abstract class AbstractCommunicationManager implements
// Security: double cookie submission pattern unless disabled by
// property
- if (!"true"
- .equals(application2
- .getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION))) {
+ if (isXSRFEnabled(application2)) {
if (bursts.length == 1 && "init".equals(bursts[0])) {
// init request; don't handle any variables, key sent in
// response.
@@ -1290,8 +1138,8 @@ public abstract class AbstractCommunicationManager implements
} else {
// ApplicationServlet has stored the security token in the
// session; check that it matched the one sent in the UIDL
- String sessId = (String) request.getSession().getAttribute(
- ApplicationConnection.UIDL_SECURITY_TOKEN_ID);
+ String sessId = (String) request
+ .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID);
if (sessId == null || !sessId.equals(bursts[0])) {
throw new InvalidUIDLSecurityKeyException(
@@ -1319,7 +1167,7 @@ public abstract class AbstractCommunicationManager implements
new CharArrayWriter());
paintAfterVariableChanges(request, response, callback,
- true, outWriter, window, false);
+ true, outWriter, root, false);
}
@@ -1331,7 +1179,7 @@ public abstract class AbstractCommunicationManager implements
* we don't have the required logic implemented on the server side. E.g.
* a component is removed in a previous burst.
*/
- return success || closingWindowName != null;
+ return success;
}
public boolean handleVariableBurst(Object source, Application app,
@@ -1385,16 +1233,6 @@ public abstract class AbstractCommunicationManager implements
}
try {
changeVariables(source, owner, m);
-
- // Special-case of closing browser-level windows:
- // track browser-windows currently open in client
- if (owner instanceof Window
- && ((Window) owner).getParent() == null) {
- final Boolean close = (Boolean) m.get("close");
- if (close != null && close.booleanValue()) {
- closingWindowName = ((Window) owner).getName();
- }
- }
} catch (Exception e) {
if (owner instanceof Component) {
handleChangeVariablesError(app, (Component) owner, e, m);
@@ -1462,7 +1300,8 @@ public abstract class AbstractCommunicationManager implements
* @return
* @throws IOException
*/
- protected String getRequestPayload(Request request) throws IOException {
+ protected String getRequestPayload(WrappedRequest request)
+ throws IOException {
int requestLength = request.getContentLength();
if (requestLength == 0) {
@@ -1526,7 +1365,7 @@ public abstract class AbstractCommunicationManager implements
if (owner instanceof AbstractField) {
try {
- handled = ((AbstractField) owner).handleError(errorEvent);
+ handled = ((AbstractField<?>) owner).handleError(errorEvent);
} catch (Exception handlerException) {
/*
* If there is an error in the component error handler we pass
@@ -1825,108 +1664,6 @@ public abstract class AbstractCommunicationManager implements
}
/**
- * TODO New method - document me!
- *
- * @param request
- * @param callback
- * @param application
- * @param assumedWindow
- * @return
- */
- protected Window doGetApplicationWindow(Request request, Callback callback,
- Application application, Window assumedWindow) {
-
- Window window = null;
-
- // If the client knows which window to use, use it if possible
- String windowClientRequestedName = request.getParameter("windowName");
-
- if (assumedWindow != null
- && application.getWindows().contains(assumedWindow)) {
- windowClientRequestedName = assumedWindow.getName();
- }
- if (windowClientRequestedName != null) {
- window = application.getWindow(windowClientRequestedName);
- if (window != null) {
- return window;
- }
- }
-
- // If client does not know what window it wants
- if (window == null && !request.isRunningInPortlet()) {
- // This is only supported if the application is running inside a
- // servlet
-
- // Get the path from URL
- String path = callback.getRequestPathInfo(request);
-
- /*
- * If the path is specified, create name from it.
- *
- * An exception is if UIDL request have come this far. This happens
- * if main window is refreshed. In that case we always return main
- * window (infamous hacky support for refreshes if only main window
- * is used). However we are not returning with main window here (we
- * will later if things work right), because the code is so cryptic
- * that nobody really knows what it does.
- */
- boolean pathMayContainWindowName = path != null
- && path.length() > 0 && !path.equals("/");
- if (pathMayContainWindowName) {
- boolean uidlRequest = path.startsWith("/UIDL");
- if (!uidlRequest) {
- String windowUrlName = null;
- if (path.charAt(0) == '/') {
- path = path.substring(1);
- }
- final int index = path.indexOf('/');
- if (index < 0) {
- windowUrlName = path;
- path = "";
- } else {
- windowUrlName = path.substring(0, index);
- path = path.substring(index + 1);
- }
-
- window = application.getWindow(windowUrlName);
- }
- }
-
- }
-
- // By default, use mainwindow
- if (window == null) {
- window = application.getMainWindow();
- // Return null if no main window was found
- if (window == null) {
- return null;
- }
- }
-
- // If the requested window is already open, resolve conflict
- if (currentlyOpenWindowsInClient.containsKey(window.getName())) {
- String newWindowName = window.getName();
-
- synchronized (AbstractCommunicationManager.class) {
- while (currentlyOpenWindowsInClient.containsKey(newWindowName)) {
- newWindowName = window.getName() + "_"
- + nextUnusedWindowSuffix++;
- }
- }
-
- window = application.getWindow(newWindowName);
-
- // If everything else fails, use main window even in case of
- // conflicts
- if (window == null) {
- window = application.getMainWindow();
- }
- }
-
- return window;
- }
-
- /**
* Ends the Application.
*
* The browser is redirected to the Application logout URL set with
@@ -1942,8 +1679,9 @@ public abstract class AbstractCommunicationManager implements
* @throws IOException
* if the writing failed due to input/output error.
*/
- private void endApplication(Request request, Response response,
- Application application) throws IOException {
+ private void endApplication(WrappedRequest request,
+ WrappedResponse response, Application application)
+ throws IOException {
String logoutUrl = application.getLogoutURL();
if (logoutUrl == null) {
@@ -1974,7 +1712,8 @@ public abstract class AbstractCommunicationManager implements
* @param outWriter
* @param response
*/
- protected void openJsonMessage(PrintWriter outWriter, Response response) {
+ protected void openJsonMessage(PrintWriter outWriter,
+ WrappedResponse response) {
// Sets the response type
response.setContentType("application/json; charset=UTF-8");
// some dirt to prevent cross site scripting
@@ -2035,7 +1774,7 @@ public abstract class AbstractCommunicationManager implements
* root window for which dirty components is to be fetched
* @return
*/
- private ArrayList<Paintable> getDirtyVisibleComponents(Window w) {
+ private ArrayList<Paintable> getDirtyVisibleComponents(Root r) {
final ArrayList<Paintable> resultset = new ArrayList<Paintable>(
dirtyPaintables);
@@ -2054,18 +1793,18 @@ public abstract class AbstractCommunicationManager implements
resultset.remove(p);
i.remove();
} else {
- Window componentsRoot = component.getWindow();
+ Root componentsRoot = component.getRoot();
if (componentsRoot == null) {
// This should not happen unless somebody has overriden
// getApplication or getWindow in an illegal way.
throw new IllegalStateException(
"component.getWindow() returned null for a component attached to the application");
}
- if (componentsRoot.getParent() != null) {
- // this is a subwindow
- componentsRoot = componentsRoot.getParent();
- }
- if (componentsRoot != w) {
+ // if (componentsRoot.getParent() != null) {
+ // // this is a subwindow
+ // componentsRoot = componentsRoot.getParent();
+ // }
+ if (componentsRoot != r) {
resultset.remove(p);
} else if (component.getParent() != null
&& !component.getParent().isVisible()) {
@@ -2107,41 +1846,6 @@ public abstract class AbstractCommunicationManager implements
}
/**
- * Implementation of {@link URIHandler.ErrorEvent} interface.
- */
- public class URIHandlerErrorImpl implements URIHandler.ErrorEvent,
- Serializable {
-
- private final URIHandler owner;
-
- private final Throwable throwable;
-
- /**
- *
- * @param owner
- * @param throwable
- */
- private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) {
- this.owner = owner;
- this.throwable = throwable;
- }
-
- /**
- * @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable()
- */
- public Throwable getThrowable() {
- return throwable;
- }
-
- /**
- * @see com.vaadin.terminal.URIHandler.ErrorEvent#getURIHandler()
- */
- public URIHandler getURIHandler() {
- return owner;
- }
- }
-
- /**
* Queues a locale to be sent to the client (browser) for date and time
* entry etc. All locale specific information is derived from server-side
* {@link Locale} instances and sent to the client when needed, eliminating
@@ -2209,80 +1913,11 @@ public abstract class AbstractCommunicationManager implements
}
- /**
- * Calls the Window URI handler for a request and returns the
- * {@link DownloadStream} returned by the handler.
- *
- * If the window is the main window of an application, the (deprecated)
- * {@link Application#handleURI(java.net.URL, String)} is called first to
- * handle {@link ApplicationResource}s, and the window handler is only
- * called if it returns null.
- *
- * @param window
- * the target window of the request
- * @param request
- * the request instance
- * @param response
- * the response to write to
- * @return DownloadStream if the request was handled and further processing
- * should be suppressed, null otherwise.
- * @see com.vaadin.terminal.URIHandler
- */
- @SuppressWarnings("deprecation")
- protected DownloadStream handleURI(Window window, Request request,
- Response response, Callback callback) {
-
- String uri = callback.getRequestPathInfo(request);
-
- // If no URI is available
- if (uri == null) {
- uri = "";
- } else {
- // Removes the leading /
- while (uri.startsWith("/") && uri.length() > 0) {
- uri = uri.substring(1);
- }
- }
-
- // Handles the uri
- try {
- URL context = application.getURL();
- if (window == application.getMainWindow()) {
- DownloadStream stream = null;
- /*
- * Application.handleURI run first. Handles possible
- * ApplicationResources.
- */
- stream = application.handleURI(context, uri);
- if (stream == null) {
- stream = window.handleURI(context, uri);
- }
- return stream;
- } else {
- // Resolve the prefix end index
- final int index = uri.indexOf('/');
- if (index > 0) {
- String prefix = uri.substring(0, index);
- URL windowContext;
- windowContext = new URL(context, prefix + "/");
- final String windowUri = (uri.length() > prefix.length() + 1) ? uri
- .substring(prefix.length() + 1) : "";
- return window.handleURI(windowContext, windowUri);
- } else {
- return null;
- }
- }
-
- } catch (final Throwable t) {
- application.getErrorHandler().terminalError(
- new URIHandlerErrorImpl(application, t));
- return null;
- }
- }
-
private final HashMap<Class<? extends Paintable>, Integer> typeToKey = new HashMap<Class<? extends Paintable>, Integer>();
private int nextTypeKey = 0;
+ private BootstrapHandler bootstrapHandler;
+
String getTagForType(Class<? extends Paintable> class1) {
Integer object = typeToKey.get(class1);
if (object == null) {
@@ -2323,6 +1958,101 @@ public abstract class AbstractCommunicationManager implements
abstract protected void cleanStreamVariable(VariableOwner owner, String name);
/**
+ * Gets the bootstrap handler that should be used for generating the pages
+ * bootstrapping applications for this communication manager.
+ *
+ * @return the bootstrap handler to use
+ */
+ private BootstrapHandler getBootstrapHandler() {
+ if (bootstrapHandler == null) {
+ bootstrapHandler = createBootstrapHandler();
+ }
+
+ return bootstrapHandler;
+ }
+
+ protected abstract BootstrapHandler createBootstrapHandler();
+
+ protected boolean handleApplicationRequest(WrappedRequest request,
+ WrappedResponse response) throws IOException {
+ return application.handleRequest(request, response);
+ }
+
+ public void handleBrowserDetailsRequest(WrappedRequest request,
+ WrappedResponse response, Application application)
+ throws IOException {
+
+ // if we do not yet have a currentRoot, it should be initialized
+ // shortly, and we should send the initial UIDL
+ boolean sendUIDL = Root.getCurrentRoot() == null;
+
+ try {
+ CombinedRequest combinedRequest = new CombinedRequest(request);
+
+ Root root = application.getRootForRequest(combinedRequest);
+ response.setContentType("application/json; charset=UTF-8");
+
+ // Use the same logic as for determined roots
+ BootstrapHandler bootstrapHandler = getBootstrapHandler();
+ BootstrapContext context = bootstrapHandler.createContext(
+ combinedRequest, response, application, root.getRootId());
+
+ String widgetset = context.getWidgetsetName();
+ String theme = context.getThemeName();
+ String themeUri = bootstrapHandler.getThemeUri(context, theme);
+
+ // TODO These are not required if it was only the init of the root
+ // that was delayed
+ JSONObject params = new JSONObject();
+ params.put("widgetset", widgetset);
+ params.put("themeUri", themeUri);
+ // Root id might have changed based on e.g. window.name
+ params.put(ApplicationConnection.ROOT_ID_PARAMETER,
+ root.getRootId());
+ if (sendUIDL) {
+ String initialUIDL = getInitialUIDL(combinedRequest, root);
+ params.put("uidl", initialUIDL);
+ }
+ response.getWriter().write(params.toString());
+ } catch (RootRequiresMoreInformationException e) {
+ // Requiring more information at this point is not allowed
+ // TODO handle in a better way
+ throw new RuntimeException(e);
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Generates the initial UIDL message that can e.g. be included in a html
+ * page to avoid a separate round trip just for getting the UIDL.
+ *
+ * @param request
+ * the request that caused the initialization
+ * @param root
+ * the root for which the UIDL should be generated
+ * @return a string with the initial UIDL message
+ * @throws PaintException
+ * if an exception occurs while painting
+ */
+ protected String getInitialUIDL(WrappedRequest request, Root root)
+ throws PaintException {
+ // TODO maybe unify writeUidlResponCe()?
+ makeAllPaintablesDirty(root);
+ StringWriter sWriter = new StringWriter();
+ PrintWriter pWriter = new PrintWriter(sWriter);
+ pWriter.print("{");
+ if (isXSRFEnabled(root.getApplication())) {
+ pWriter.print(getSecurityKeyUIDL(request));
+ }
+ writeUidlResponce(true, pWriter, root, false);
+ pWriter.print("}");
+ String initialUIDL = sWriter.toString();
+ return initialUIDL;
+ }
+
+ /**
* Stream that extracts content from another stream until the boundary
* string is encountered.
*
diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet.java
deleted file mode 100644
index f971bcbc90..0000000000
--- a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.terminal.gwt.server;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.portlet.ActionRequest;
-import javax.portlet.ActionResponse;
-import javax.portlet.PortalContext;
-import javax.portlet.Portlet;
-import javax.portlet.PortletConfig;
-import javax.portlet.PortletException;
-import javax.portlet.PortletRequestDispatcher;
-import javax.portlet.PortletSession;
-import javax.portlet.RenderRequest;
-import javax.portlet.RenderResponse;
-
-import com.liferay.portal.kernel.util.PropsUtil;
-import com.vaadin.Application;
-
-/**
- * Portlet main class for Portlet 1.0 (JSR-168) portlets which consist of a
- * portlet and a servlet. For Portlet 2.0 (JSR-286, no servlet required), use
- * {@link ApplicationPortlet2} instead.
- */
-@SuppressWarnings("serial")
-public class ApplicationPortlet implements Portlet, Serializable {
- // portlet configuration parameters
- private static final String PORTLET_PARAMETER_APPLICATION = "application";
- private static final String PORTLET_PARAMETER_STYLE = "style";
- private static final String PORTLET_PARAMETER_WIDGETSET = "widgetset";
-
- // The application to show
- protected String app = null;
- // some applications might require forced height (and, more seldom, width)
- protected String style = null; // e.g "height:500px;"
- // force the portlet to use this widgetset - portlet level setting
- protected String portletWidgetset = null;
-
- public void destroy() {
-
- }
-
- public void init(PortletConfig config) throws PortletException {
- app = config.getInitParameter(PORTLET_PARAMETER_APPLICATION);
- if (app == null) {
- throw new PortletException(
- "No porlet application url defined in portlet.xml. Define the '"
- + PORTLET_PARAMETER_APPLICATION
- + "' init parameter to be the servlet deployment path.");
- }
- style = config.getInitParameter(PORTLET_PARAMETER_STYLE);
- // enable forcing the selection of the widgetset in portlet
- // configuration for a single portlet (backwards compatibility)
- portletWidgetset = config.getInitParameter(PORTLET_PARAMETER_WIDGETSET);
- }
-
- public void processAction(ActionRequest request, ActionResponse response)
- throws PortletException, IOException {
- PortletApplicationContext.dispatchRequest(this, request, response);
- }
-
- public void render(RenderRequest request, RenderResponse response)
- throws PortletException, IOException {
-
- // display the Vaadin application
- writeAjaxWindow(request, response);
- }
-
- protected void writeAjaxWindow(RenderRequest request,
- RenderResponse response) throws IOException {
-
- response.setContentType("text/html");
- if (app != null) {
- PortletSession sess = request.getPortletSession();
- PortletApplicationContext ctx = PortletApplicationContext
- .getApplicationContext(sess);
-
- PortletRequestDispatcher dispatcher = sess.getPortletContext()
- .getRequestDispatcher("/" + app);
-
- try {
- // portal-wide settings
- PortalContext portalCtx = request.getPortalContext();
-
- boolean isLifeRay = portalCtx.getPortalInfo().toLowerCase()
- .contains("liferay");
-
- request.setAttribute(ApplicationServlet.REQUEST_FRAGMENT,
- "true");
-
- // fixed base theme to use - all portal pages with Vaadin
- // applications will load this exactly once
- String portalTheme = getPortalProperty(
- Constants.PORTAL_PARAMETER_VAADIN_THEME, portalCtx);
-
- String portalWidgetset = getPortalProperty(
- Constants.PORTAL_PARAMETER_VAADIN_WIDGETSET, portalCtx);
-
- // location of the widgetset(s) and default theme (to which
- // /VAADIN/widgetsets/...
- // is appended)
- String portalResourcePath = getPortalProperty(
- Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH,
- portalCtx);
-
- if (portalResourcePath != null) {
- // if portalResourcePath is defined, set it as a request
- // parameter which will override the default location in
- // servlet
- request.setAttribute(
- ApplicationServlet.REQUEST_VAADIN_STATIC_FILE_PATH,
- portalResourcePath);
- }
-
- // - if the user has specified a widgetset for this portlet, use
- // it from the portlet (not fully supported)
- // - otherwise, if specified, use the portal-wide widgetset
- // and widgetset path settings (recommended)
- // - finally, default to use the default widgetset if nothing
- // else is found
- if (portletWidgetset != null) {
- request.setAttribute(ApplicationServlet.REQUEST_WIDGETSET,
- portletWidgetset);
- }
- if (portalWidgetset != null) {
- request.setAttribute(
- ApplicationServlet.REQUEST_SHARED_WIDGETSET,
- portalWidgetset);
- }
-
- if (style != null) {
- request.setAttribute(ApplicationServlet.REQUEST_APPSTYLE,
- style);
- }
-
- // portalTheme is only used if the shared portal resource
- // directory is defined
- if (portalTheme != null && portalResourcePath != null) {
- request.setAttribute(
- ApplicationServlet.REQUEST_DEFAULT_THEME,
- portalTheme);
-
- String defaultThemeUri = null;
- defaultThemeUri = portalResourcePath + "/"
- + AbstractApplicationServlet.THEME_DIRECTORY_PATH
- + portalTheme;
- /*
- * Make sure portal default Vaadin theme is included in DOM.
- * Vaadin portlet themes do not "inherit" base theme, so we
- * need to force loading of the common base theme.
- */
- OutputStream out = response.getPortletOutputStream();
-
- // Using portal-wide theme
- String loadDefaultTheme = ("<script type=\"text/javascript\">\n"
- + "if(!vaadin) { var vaadin = {} } \n"
- + "if(!vaadin.themesLoaded) { vaadin.themesLoaded = {} } \n"
- + "if(!vaadin.themesLoaded['"
- + portalTheme
- + "']) {\n"
- + "var stylesheet = document.createElement('link');\n"
- + "stylesheet.setAttribute('rel', 'stylesheet');\n"
- + "stylesheet.setAttribute('type', 'text/css');\n"
- + "stylesheet.setAttribute('href', '"
- + defaultThemeUri
- + "/styles.css');\n"
- + "document.getElementsByTagName('head')[0].appendChild(stylesheet);\n"
- + "vaadin.themesLoaded['"
- + portalTheme
- + "'] = true;\n}\n" + "</script>\n");
- out.write(loadDefaultTheme.getBytes());
- }
-
- dispatcher.include(request, response);
-
- if (isLifeRay) {
- /*
- * Temporary support to heartbeat Liferay session when using
- * Vaadin based portlet. We hit an extra xhr to liferay
- * servlet to extend the session lifetime after each Vaadin
- * request. This hack can be removed when supporting portlet
- * 2.0 and resourceRequests.
- *
- * TODO make this configurable, this is not necessary with
- * some custom session configurations.
- */
- OutputStream out = response.getPortletOutputStream();
-
- String lifeRaySessionHearbeatHack = ("<script type=\"text/javascript\">"
- + "if(!vaadin.postRequestHooks) {"
- + " vaadin.postRequestHooks = {};"
- + "}"
- + "vaadin.postRequestHooks.liferaySessionHeartBeat = function() {"
- + " if (Liferay && Liferay.Session && Liferay.Session.setCookie) {"
- + " Liferay.Session.setCookie();"
- + " }"
- + "};" + "</script>");
- out.write(lifeRaySessionHearbeatHack.getBytes());
- }
-
- } catch (PortletException e) {
- PrintWriter out = response.getWriter();
- out.print("<h1>Servlet include failed!</h1>");
- Logger.getLogger(AbstractApplicationPortlet.class.getName())
- .log(Level.WARNING, "Servlet include failed", e);
- ctx.setPortletApplication(this, null);
- return;
- }
-
- Application app = (Application) request
- .getAttribute(Application.class.getName());
- ctx.setPortletApplication(this, app);
- ctx.firePortletRenderRequest(this, request, response);
-
- }
- }
-
- private String getPortalProperty(String name, PortalContext context) {
- boolean isLifeRay = context.getPortalInfo().toLowerCase()
- .contains("liferay");
-
- // TODO test on non-LifeRay platforms
-
- String value;
- if (isLifeRay) {
- value = getLifeRayPortalProperty(name);
- } else {
- value = context.getProperty(name);
- }
-
- return value;
- }
-
- private String getLifeRayPortalProperty(String name) {
- String value;
- try {
- value = PropsUtil.get(name);
- } catch (Exception e) {
- value = null;
- }
- return value;
- }
-}
diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java
index 3e15c1cf8f..7a46a07e6c 100644
--- a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java
+++ b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java
@@ -8,6 +8,7 @@ import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import com.vaadin.Application;
+import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException;
/**
* TODO Write documentation, fix JavaDoc tags.
@@ -18,23 +19,16 @@ public class ApplicationPortlet2 extends AbstractApplicationPortlet {
private Class<? extends Application> applicationClass;
- @SuppressWarnings("unchecked")
@Override
public void init(PortletConfig config) throws PortletException {
super.init(config);
- final String applicationClassName = config
- .getInitParameter("application");
- if (applicationClassName == null) {
- throw new PortletException(
- "Application not specified in portlet parameters");
- }
-
try {
- applicationClass = (Class<? extends Application>) getClassLoader()
- .loadClass(applicationClassName);
- } catch (final ClassNotFoundException e) {
- throw new PortletException("Failed to load application class: "
- + applicationClassName);
+ applicationClass = ServletPortletHelper.getApplicationClass(
+ config.getInitParameter("application"),
+ config.getInitParameter(Application.ROOT_PARAMETER),
+ getClassLoader());
+ } catch (ApplicationClassException e) {
+ throw new PortletException(e);
}
}
diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java
new file mode 100644
index 0000000000..7cf66d5fcf
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java
@@ -0,0 +1,54 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.ApplicationResource;
+import com.vaadin.terminal.DownloadStream;
+import com.vaadin.terminal.RequestHandler;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
+
+public class ApplicationResourceHandler implements RequestHandler {
+ private static final Pattern APP_RESOURCE_PATTERN = Pattern
+ .compile("^/?APP/(\\d+)/.*");
+
+ public boolean handleRequest(Application application,
+ WrappedRequest request, WrappedResponse response)
+ throws IOException {
+ // Check for application resources
+ String requestPath = request.getRequestPathInfo();
+ if (requestPath == null) {
+ return false;
+ }
+ Matcher resourceMatcher = APP_RESOURCE_PATTERN.matcher(requestPath);
+
+ if (resourceMatcher.matches()) {
+ ApplicationResource resource = application
+ .getResource(resourceMatcher.group(1));
+ if (resource != null) {
+ DownloadStream stream = resource.getStream();
+ if (stream != null) {
+ stream.setCacheTime(resource.getCacheTime());
+ stream.writeTo(response);
+ return true;
+ }
+ }
+ // We get here if the url looks like an application resource but no
+ // resource can be served
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,
+ request.getRequestPathInfo() + " can not be found");
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java
index a9eaa1bb82..064d2b16af 100644
--- a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java
@@ -15,10 +15,29 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.vaadin.Application;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.ui.Root;
@SuppressWarnings("serial")
public class ApplicationRunnerServlet extends AbstractApplicationServlet {
+ /**
+ * Internal implementation of an application with a dynamically selected
+ * Root implementation;
+ */
+ private static class RootRunnerApplication extends Application {
+ private final Class<?> runnableClass;
+
+ private RootRunnerApplication(Class<?> runnableClass) {
+ this.runnableClass = runnableClass;
+ }
+
+ @Override
+ protected String getRootClassName(WrappedRequest request) {
+ return runnableClass.getCanonicalName();
+ }
+ }
+
private static final Logger logger = Logger
.getLogger(ApplicationRunnerServlet.class.getName());
@@ -43,8 +62,11 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet {
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
this.request.set(request);
- super.service(request, response);
- this.request.set(null);
+ try {
+ super.service(request, response);
+ } finally {
+ this.request.set(null);
+ }
}
@Override
@@ -65,8 +87,15 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet {
// Creates a new application instance
try {
- final Application application = getApplicationClass().newInstance();
- return application;
+ final Class<?> classToRun = getClassToRun();
+ if (Root.class.isAssignableFrom(classToRun)) {
+ return new RootRunnerApplication(classToRun);
+ } else if (Application.class.isAssignableFrom(classToRun)) {
+ return (Application) classToRun.newInstance();
+ } else {
+ throw new ServletException(classToRun.getCanonicalName()
+ + " is neither an Application nor a Root");
+ }
} catch (final IllegalAccessException e) {
throw new ServletException(e);
} catch (final InstantiationException e) {
@@ -150,28 +179,37 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet {
return uris;
}
- @SuppressWarnings("unchecked")
@Override
protected Class<? extends Application> getApplicationClass()
throws ClassNotFoundException {
+ Class<?> classToRun = getClassToRun();
+ if (Root.class.isAssignableFrom(classToRun)) {
+ return RootRunnerApplication.class;
+ } else if (Application.class.isAssignableFrom(classToRun)) {
+ return classToRun.asSubclass(Application.class);
+ } else {
+ throw new ClassCastException(classToRun.getCanonicalName()
+ + " is not an Application nor a Root");
+ }
+ }
+
+ private Class<?> getClassToRun() throws ClassNotFoundException {
// TODO use getClassLoader() ?
- Class<? extends Application> appClass = null;
+ Class<?> appClass = null;
String baseName = getApplicationRunnerApplicationClassName(request
.get());
try {
- appClass = (Class<? extends Application>) getClass()
- .getClassLoader().loadClass(baseName);
+ appClass = getClass().getClassLoader().loadClass(baseName);
return appClass;
} catch (Exception e) {
//
if (defaultPackages != null) {
for (int i = 0; i < defaultPackages.length; i++) {
try {
- appClass = (Class<? extends Application>) getClass()
- .getClassLoader().loadClass(
- defaultPackages[i] + "." + baseName);
+ appClass = getClass().getClassLoader().loadClass(
+ defaultPackages[i] + "." + baseName);
} catch (ClassNotFoundException ee) {
// Ignore as this is expected for many packages
} catch (Exception e2) {
@@ -215,4 +253,16 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet {
return staticFilesPath;
}
+ @Override
+ protected WrappedHttpServletRequest createWrappedRequest(
+ HttpServletRequest request) {
+ return new WrappedHttpServletRequest(request,
+ getDeploymentConfiguration()) {
+ @Override
+ public String getRequestPathInfo() {
+ return ApplicationRunnerServlet.this.getRequestPathInfo(this);
+ }
+ };
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java
index 8ad763f5d1..2c4d38ef24 100644
--- a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java
@@ -8,6 +8,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import com.vaadin.Application;
+import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException;
/**
* This servlet connects a Vaadin Application to Web.
@@ -35,7 +36,6 @@ public class ApplicationServlet extends AbstractApplicationServlet {
* if an exception has occurred that interferes with the
* servlet's normal operation.
*/
- @SuppressWarnings("unchecked")
@Override
public void init(javax.servlet.ServletConfig servletConfig)
throws javax.servlet.ServletException {
@@ -44,20 +44,13 @@ public class ApplicationServlet extends AbstractApplicationServlet {
// Loads the application class using the same class loader
// as the servlet itself
- // Gets the application class name
- final String applicationClassName = servletConfig
- .getInitParameter("application");
- if (applicationClassName == null) {
- throw new ServletException(
- "Application not specified in servlet parameters");
- }
-
try {
- applicationClass = (Class<? extends Application>) getClassLoader()
- .loadClass(applicationClassName);
- } catch (final ClassNotFoundException e) {
- throw new ServletException("Failed to load application class: "
- + applicationClassName);
+ applicationClass = ServletPortletHelper.getApplicationClass(
+ servletConfig.getInitParameter("application"),
+ servletConfig.getInitParameter(Application.ROOT_PARAMETER),
+ getClassLoader());
+ } catch (ApplicationClassException e) {
+ throw new ServletException(e);
}
}
@@ -84,4 +77,4 @@ public class ApplicationServlet extends AbstractApplicationServlet {
throws ClassNotFoundException {
return applicationClass;
}
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
new file mode 100644
index 0000000000..84f87124d3
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
@@ -0,0 +1,602 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.vaadin.Application;
+import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.external.json.JSONException;
+import com.vaadin.external.json.JSONObject;
+import com.vaadin.terminal.DeploymentConfiguration;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.RequestHandler;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.ui.Root;
+
+public abstract class BootstrapHandler implements RequestHandler {
+
+ protected class BootstrapContext implements Serializable {
+
+ private final WrappedResponse response;
+ private final WrappedRequest request;
+ private final Application application;
+ private final Integer rootId;
+
+ private Writer writer;
+ private Root root;
+ private String widgetsetName;
+ private String themeName;
+ private String appId;
+
+ private boolean rootFetched = false;
+
+ public BootstrapContext(WrappedResponse response,
+ WrappedRequest request, Application application, Integer rootId) {
+ this.response = response;
+ this.request = request;
+ this.application = application;
+ this.rootId = rootId;
+ }
+
+ public WrappedResponse getResponse() {
+ return response;
+ }
+
+ public WrappedRequest getRequest() {
+ return request;
+ }
+
+ public Application getApplication() {
+ return application;
+ }
+
+ public Writer getWriter() throws IOException {
+ if (writer == null) {
+ response.setContentType("text/html");
+ writer = new BufferedWriter(new OutputStreamWriter(
+ response.getOutputStream(), "UTF-8"));
+ }
+ return writer;
+ }
+
+ public Integer getRootId() {
+ return rootId;
+ }
+
+ public Root getRoot() {
+ if (!rootFetched) {
+ root = Root.getCurrentRoot();
+ rootFetched = true;
+ }
+ return root;
+ }
+
+ public String getWidgetsetName() {
+ if (widgetsetName == null) {
+ Root root = getRoot();
+ if (root != null) {
+ widgetsetName = getWidgetsetForRoot(this);
+ }
+ }
+ return widgetsetName;
+ }
+
+ public String getThemeName() {
+ if (themeName == null) {
+ Root root = getRoot();
+ if (root != null) {
+ themeName = findAndEscapeThemeName(this);
+ }
+ }
+ return themeName;
+ }
+
+ public String getAppId() {
+ if (appId == null) {
+ appId = getApplicationId(this);
+ }
+ return appId;
+ }
+
+ }
+
+ public boolean handleRequest(Application application,
+ WrappedRequest request, WrappedResponse response)
+ throws IOException {
+
+ // TODO Should all urls be handled here?
+ Integer rootId = null;
+ try {
+ Root root = application.getRootForRequest(request);
+ if (root == null) {
+ writeError(response, new Throwable("No Root found"));
+ return true;
+ }
+
+ rootId = Integer.valueOf(root.getRootId());
+ } catch (RootRequiresMoreInformationException e) {
+ // Just keep going without rootId
+ }
+
+ try {
+ writeBootstrapPage(request, response, application, rootId);
+ } catch (JSONException e) {
+ writeError(response, e);
+ }
+
+ return true;
+ }
+
+ protected final void writeBootstrapPage(WrappedRequest request,
+ WrappedResponse response, Application application, Integer rootId)
+ throws IOException, JSONException {
+
+ BootstrapContext context = createContext(request, response,
+ application, rootId);
+
+ DeploymentConfiguration deploymentConfiguration = request
+ .getDeploymentConfiguration();
+
+ boolean standalone = deploymentConfiguration.isStandalone(request);
+ if (standalone) {
+ setBootstrapPageHeaders(context);
+ writeBootstrapPageHtmlHeadStart(context);
+ writeBootstrapPageHtmlHeader(context);
+ writeBootstrapPageHtmlBodyStart(context);
+ }
+
+ // TODO include initial UIDL in the scripts?
+ writeBootstrapPageHtmlVaadinScripts(context);
+
+ writeBootstrapPageHtmlMainDiv(context);
+
+ Writer page = context.getWriter();
+ if (standalone) {
+ page.write("</body>\n</html>\n");
+ }
+
+ page.close();
+ }
+
+ public BootstrapContext createContext(WrappedRequest request,
+ WrappedResponse response, Application application, Integer rootId) {
+ BootstrapContext context = new BootstrapContext(response, request,
+ application, rootId);
+ return context;
+ }
+
+ protected String getMainDivStyle(BootstrapContext context) {
+ return null;
+ }
+
+ /**
+ * Creates and returns a unique ID for the DIV where the application is to
+ * be rendered.
+ *
+ * @param context
+ *
+ * @return the id to use in the DOM
+ */
+ protected abstract String getApplicationId(BootstrapContext context);
+
+ public String getWidgetsetForRoot(BootstrapContext context) {
+ Root root = context.getRoot();
+ WrappedRequest request = context.getRequest();
+
+ String widgetset = root.getApplication().getWidgetsetForRoot(root);
+ if (widgetset == null) {
+ widgetset = request.getDeploymentConfiguration()
+ .getConfiguredWidgetset(request);
+ }
+
+ widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset);
+ return widgetset;
+ }
+
+ /**
+ * Method to write the div element into which that actual Vaadin application
+ * is rendered.
+ * <p>
+ * Override this method if you want to add some custom html around around
+ * the div element into which the actual Vaadin application will be
+ * rendered.
+ *
+ * @param context
+ *
+ * @throws IOException
+ */
+ protected void writeBootstrapPageHtmlMainDiv(BootstrapContext context)
+ throws IOException {
+ Writer page = context.getWriter();
+ String style = getMainDivStyle(context);
+
+ /*- Add classnames;
+ * .v-app
+ * .v-app-loading
+ * .v-app-<simpleName for app class>
+ *- Additionally added from javascript:
+ * .v-theme-<themeName, remove non-alphanum>
+ */
+
+ String appClass = "v-app-"
+ + getApplicationCSSClassName(context.getApplication());
+
+ String classNames = "v-app " + appClass;
+
+ if (style != null && style.length() != 0) {
+ style = " style=\"" + style + "\"";
+ }
+ page.write("<div id=\"" + context.getAppId() + "\" class=\""
+ + classNames + "\"" + style + ">");
+ page.write("<div class=\"v-app-loading\"></div>");
+ page.write("</div>\n");
+ page.write("<noscript>" + getNoScriptMessage() + "</noscript>");
+ }
+
+ /**
+ * Returns a message printed for browsers without scripting support or if
+ * browsers scripting support is disabled.
+ */
+ protected String getNoScriptMessage() {
+ return "You have to enable javascript in your browser to use an application built with Vaadin.";
+ }
+
+ /**
+ * Returns the application class identifier for use in the application CSS
+ * class name in the root DIV. The application CSS class name is of form
+ * "v-app-"+getApplicationCSSClassName().
+ *
+ * This method should normally not be overridden.
+ *
+ * @return The CSS class name to use in combination with "v-app-".
+ */
+ protected String getApplicationCSSClassName(Application application) {
+ return application.getClass().getSimpleName();
+ }
+
+ /**
+ *
+ * Method to open the body tag of the html kickstart page.
+ * <p>
+ * This method is responsible for closing the head tag and opening the body
+ * tag.
+ * <p>
+ * Override this method if you want to add some custom html to the page.
+ *
+ * @throws IOException
+ */
+ protected void writeBootstrapPageHtmlBodyStart(BootstrapContext context)
+ throws IOException {
+ Writer page = context.getWriter();
+ page.write("\n</head>\n<body scroll=\"auto\" class=\""
+ + ApplicationConnection.GENERATED_BODY_CLASSNAME + "\">\n");
+ }
+
+ /**
+ * Method to write the script part of the page which loads needed Vaadin
+ * scripts and themes.
+ * <p>
+ * Override this method if you want to add some custom html around scripts.
+ *
+ * @param context
+ *
+ * @throws IOException
+ * @throws JSONException
+ */
+ protected void writeBootstrapPageHtmlVaadinScripts(BootstrapContext context)
+ throws IOException, JSONException {
+ WrappedRequest request = context.getRequest();
+ Writer page = context.getWriter();
+
+ DeploymentConfiguration deploymentConfiguration = request
+ .getDeploymentConfiguration();
+ String staticFileLocation = deploymentConfiguration
+ .getStaticFileLocation(request);
+
+ page.write("<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" "
+ + "style=\"position:absolute;width:0;height:0;border:0;overflow:"
+ + "hidden;\" src=\"javascript:false\"></iframe>");
+
+ String bootstrapLocation = staticFileLocation
+ + "/VAADIN/vaadinBootstrap.js";
+ page.write("<script type=\"text/javascript\" src=\"");
+ page.write(bootstrapLocation);
+ page.write("\"></script>\n");
+
+ page.write("<script type=\"text/javascript\">\n");
+ page.write("//<![CDATA[\n");
+ page.write("if (!window.vaadin) alert("
+ + JSONObject.quote("Failed to load the bootstrap javascript: "
+ + bootstrapLocation) + ");\n");
+
+ writeMainScriptTagContents(context);
+ page.write("//]]>\n</script>\n");
+ }
+
+ protected void writeMainScriptTagContents(BootstrapContext context)
+ throws JSONException, IOException {
+ JSONObject defaults = getDefaultParameters(context);
+ JSONObject appConfig = getApplicationParameters(context);
+
+ boolean isDebug = !context.getApplication().isProductionMode();
+ Writer page = context.getWriter();
+
+ page.write("vaadin.setDefaults(");
+ printJsonObject(page, defaults, isDebug);
+ page.write(");\n");
+
+ page.write("vaadin.initApplication(\"");
+ page.write(context.getAppId());
+ page.write("\",");
+ printJsonObject(page, appConfig, isDebug);
+ page.write(");\n");
+ }
+
+ private static void printJsonObject(Writer page, JSONObject jsonObject,
+ boolean isDebug) throws IOException, JSONException {
+ if (isDebug) {
+ page.write(jsonObject.toString(4));
+ } else {
+ page.write(jsonObject.toString());
+ }
+ }
+
+ protected JSONObject getApplicationParameters(BootstrapContext context)
+ throws JSONException, PaintException {
+ Application application = context.getApplication();
+ Integer rootId = context.getRootId();
+
+ JSONObject appConfig = new JSONObject();
+
+ if (rootId != null) {
+ appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId);
+ }
+
+ if (context.getThemeName() != null) {
+ appConfig.put("themeUri",
+ getThemeUri(context, context.getThemeName()));
+ }
+
+ JSONObject versionInfo = new JSONObject();
+ versionInfo.put("vaadinVersion", AbstractApplicationServlet.VERSION);
+ versionInfo.put("applicationVersion", application.getVersion());
+ appConfig.put("versionInfo", versionInfo);
+
+ appConfig.put("widgetset", context.getWidgetsetName());
+
+ if (rootId == null || application.isRootInitPending(rootId.intValue())) {
+ appConfig.put("initialPath", context.getRequest()
+ .getRequestPathInfo());
+
+ Map<String, String[]> parameterMap = context.getRequest()
+ .getParameterMap();
+ appConfig.put("initialParams", parameterMap);
+ } else {
+ // write the initial UIDL into the config
+ appConfig.put("uidl",
+ getInitialUIDL(context.getRequest(), context.getRoot()));
+ }
+
+ return appConfig;
+ }
+
+ protected JSONObject getDefaultParameters(BootstrapContext context)
+ throws JSONException {
+ JSONObject defaults = new JSONObject();
+
+ WrappedRequest request = context.getRequest();
+ Application application = context.getApplication();
+
+ // Get system messages
+ Application.SystemMessages systemMessages = AbstractApplicationServlet
+ .getSystemMessages(application.getClass());
+ if (systemMessages != null) {
+ // Write the CommunicationError -message to client
+ JSONObject comErrMsg = new JSONObject();
+ comErrMsg.put("caption",
+ systemMessages.getCommunicationErrorCaption());
+ comErrMsg.put("message",
+ systemMessages.getCommunicationErrorMessage());
+ comErrMsg.put("url", systemMessages.getCommunicationErrorURL());
+
+ defaults.put("comErrMsg", comErrMsg);
+
+ JSONObject authErrMsg = new JSONObject();
+ authErrMsg.put("caption",
+ systemMessages.getAuthenticationErrorCaption());
+ authErrMsg.put("message",
+ systemMessages.getAuthenticationErrorMessage());
+ authErrMsg.put("url", systemMessages.getAuthenticationErrorURL());
+
+ defaults.put("authErrMsg", authErrMsg);
+ }
+
+ DeploymentConfiguration deploymentConfiguration = request
+ .getDeploymentConfiguration();
+ String staticFileLocation = deploymentConfiguration
+ .getStaticFileLocation(request);
+ String widgetsetBase = staticFileLocation + "/"
+ + AbstractApplicationServlet.WIDGETSET_DIRECTORY_PATH;
+ defaults.put("widgetsetBase", widgetsetBase);
+
+ if (!application.isProductionMode()) {
+ defaults.put("debug", true);
+ }
+
+ if (deploymentConfiguration.isStandalone(request)) {
+ defaults.put("standalone", true);
+ }
+
+ defaults.put("appUri", getAppUri(context));
+
+ return defaults;
+ }
+
+ protected abstract String getAppUri(BootstrapContext context);
+
+ /**
+ * Method to write the contents of head element in html kickstart page.
+ * <p>
+ * Override this method if you want to add some custom html to the header of
+ * the page.
+ *
+ * @throws IOException
+ */
+ protected void writeBootstrapPageHtmlHeader(BootstrapContext context)
+ throws IOException {
+ Writer page = context.getWriter();
+ String themeName = context.getThemeName();
+
+ page.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n");
+
+ // Chrome frame in all versions of IE (only if Chrome frame is
+ // installed)
+ page.write("<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\"/>\n");
+
+ page.write("<style type=\"text/css\">"
+ + "html, body {height:100%;margin:0;}</style>");
+
+ // Add favicon links
+ if (themeName != null) {
+ String themeUri = getThemeUri(context, themeName);
+ page.write("<link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\" href=\""
+ + themeUri + "/favicon.ico\" />");
+ page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\""
+ + themeUri + "/favicon.ico\" />");
+ }
+
+ Root root = context.getRoot();
+ String title = ((root == null || root.getCaption() == null) ? "Vaadin "
+ + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption());
+
+ page.write("<title>"
+ + AbstractApplicationServlet.safeEscapeForHtml(title)
+ + "</title>");
+ }
+
+ /**
+ * Method to set http request headers for the Vaadin kickstart page.
+ * <p>
+ * Override this method if you need to customize http headers of the page.
+ *
+ * @param context
+ */
+ protected void setBootstrapPageHeaders(BootstrapContext context) {
+ WrappedResponse response = context.getResponse();
+
+ // Window renders are not cacheable
+ response.setHeader("Cache-Control", "no-cache");
+ response.setHeader("Pragma", "no-cache");
+ response.setDateHeader("Expires", 0);
+ response.setContentType("text/html; charset=UTF-8");
+ }
+
+ /**
+ * Method to write the beginning of the html page.
+ * <p>
+ * This method is responsible for writing appropriate doc type declarations
+ * and to open html and head tags.
+ * <p>
+ * Override this method if you want to add some custom html to the very
+ * beginning of the page.
+ *
+ * @param context
+ * @throws IOException
+ */
+ protected void writeBootstrapPageHtmlHeadStart(BootstrapContext context)
+ throws IOException {
+ Writer page = context.getWriter();
+
+ // write html header
+ page.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD "
+ + "XHTML 1.0 Transitional//EN\" "
+ + "\"http://www.w3.org/TR/xhtml1/"
+ + "DTD/xhtml1-transitional.dtd\">\n");
+
+ page.write("<html xmlns=\"http://www.w3.org/1999/xhtml\""
+ + ">\n<head>\n");
+ }
+
+ /**
+ * Get the URI for the application theme.
+ *
+ * A portal-wide default theme is fetched from the portal shared resource
+ * directory (if any), other themes from the portlet.
+ *
+ * @param context
+ * @param themeName
+ *
+ * @return
+ */
+ public String getThemeUri(BootstrapContext context, String themeName) {
+ WrappedRequest request = context.getRequest();
+ final String staticFilePath = request.getDeploymentConfiguration()
+ .getStaticFileLocation(request);
+ return staticFilePath + "/"
+ + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName;
+ }
+
+ /**
+ * Override if required
+ *
+ * @param context
+ * @return
+ */
+ public String getThemeName(BootstrapContext context) {
+ return context.getApplication().getThemeForRoot(context.getRoot());
+ }
+
+ /**
+ * Don not override.
+ *
+ * @param context
+ * @return
+ */
+ public String findAndEscapeThemeName(BootstrapContext context) {
+ String themeName = getThemeName(context);
+ if (themeName == null) {
+ WrappedRequest request = context.getRequest();
+ themeName = request.getDeploymentConfiguration()
+ .getConfiguredTheme(request);
+ }
+
+ // XSS preventation, theme names shouldn't contain special chars anyway.
+ // The servlet denies them via url parameter.
+ themeName = AbstractApplicationServlet.stripSpecialChars(themeName);
+
+ return themeName;
+ }
+
+ protected void writeError(WrappedResponse response, Throwable e)
+ throws IOException {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+ e.getLocalizedMessage());
+ }
+
+ /**
+ * Gets the initial UIDL message to send to the client.
+ *
+ * @param request
+ * the originating request
+ * @param root
+ * the root for which the UIDL should be generated
+ * @return a string with the initial UIDL message
+ * @throws PaintException
+ * if an exception occurs while painting the components
+ */
+ protected abstract String getInitialUIDL(WrappedRequest request, Root root)
+ throws PaintException;
+
+}
diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
index 9c67a03bb3..3a9b8ff2db 100644
--- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
@@ -6,24 +6,22 @@ package com.vaadin.terminal.gwt.server;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
+import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
+import javax.servlet.ServletContext;
import com.vaadin.Application;
-import com.vaadin.terminal.ApplicationResource;
-import com.vaadin.terminal.DownloadStream;
+import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.Paintable;
import com.vaadin.terminal.StreamVariable;
import com.vaadin.terminal.VariableOwner;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
import com.vaadin.ui.Component;
-import com.vaadin.ui.Window;
+import com.vaadin.ui.Root;
/**
* Application manager processes changes and paints for single application
@@ -42,150 +40,6 @@ import com.vaadin.ui.Window;
public class CommunicationManager extends AbstractCommunicationManager {
/**
- * Concrete wrapper class for {@link HttpServletRequest}.
- *
- * @see Request
- */
- private static class HttpServletRequestWrapper implements Request {
-
- private final HttpServletRequest request;
-
- public HttpServletRequestWrapper(HttpServletRequest request) {
- this.request = request;
- }
-
- public Object getAttribute(String name) {
- return request.getAttribute(name);
- }
-
- public int getContentLength() {
- return request.getContentLength();
- }
-
- public InputStream getInputStream() throws IOException {
- return request.getInputStream();
- }
-
- public String getParameter(String name) {
- return request.getParameter(name);
- }
-
- public String getRequestID() {
- return "RequestURL:" + request.getRequestURI();
- }
-
- public Session getSession() {
- return new HttpSessionWrapper(request.getSession());
- }
-
- public Object getWrappedRequest() {
- return request;
- }
-
- public boolean isRunningInPortlet() {
- return false;
- }
-
- public void setAttribute(String name, Object o) {
- request.setAttribute(name, o);
- }
- }
-
- /**
- * Concrete wrapper class for {@link HttpServletResponse}.
- *
- * @see Response
- */
- private static class HttpServletResponseWrapper implements Response {
-
- private final HttpServletResponse response;
-
- public HttpServletResponseWrapper(HttpServletResponse response) {
- this.response = response;
- }
-
- public OutputStream getOutputStream() throws IOException {
- return response.getOutputStream();
- }
-
- public Object getWrappedResponse() {
- return response;
- }
-
- public void setContentType(String type) {
- response.setContentType(type);
- }
-
- }
-
- /**
- * Concrete wrapper class for {@link HttpSession}.
- *
- * @see Session
- */
- private static class HttpSessionWrapper implements Session {
-
- private final HttpSession session;
-
- public HttpSessionWrapper(HttpSession session) {
- this.session = session;
- }
-
- public Object getAttribute(String name) {
- return session.getAttribute(name);
- }
-
- public int getMaxInactiveInterval() {
- return session.getMaxInactiveInterval();
- }
-
- public Object getWrappedSession() {
- return session;
- }
-
- public boolean isNew() {
- return session.isNew();
- }
-
- public void setAttribute(String name, Object o) {
- session.setAttribute(name, o);
- }
-
- }
-
- private static class AbstractApplicationServletWrapper implements Callback {
-
- private final AbstractApplicationServlet servlet;
-
- public AbstractApplicationServletWrapper(
- AbstractApplicationServlet servlet) {
- this.servlet = servlet;
- }
-
- public void criticalNotification(Request request, Response response,
- String cap, String msg, String details, String outOfSyncURL)
- throws IOException {
- servlet.criticalNotification(
- (HttpServletRequest) request.getWrappedRequest(),
- (HttpServletResponse) response.getWrappedResponse(), cap,
- msg, details, outOfSyncURL);
- }
-
- public String getRequestPathInfo(Request request) {
- return servlet.getRequestPathInfo((HttpServletRequest) request
- .getWrappedRequest());
- }
-
- public InputStream getThemeResourceAsStream(String themeName,
- String resource) throws IOException {
- return servlet.getServletContext().getResourceAsStream(
- "/" + AbstractApplicationServlet.THEME_DIRECTORY_PATH
- + themeName + "/" + resource);
- }
-
- }
-
- /**
* @deprecated use {@link #CommunicationManager(Application)} instead
* @param application
* @param applicationServlet
@@ -215,15 +69,15 @@ public class CommunicationManager extends AbstractCommunicationManager {
* @throws IOException
* @throws InvalidUIDLSecurityKeyException
*/
- public void handleFileUpload(HttpServletRequest request,
- HttpServletResponse response) throws IOException,
+ public void handleFileUpload(WrappedRequest request,
+ WrappedResponse response) throws IOException,
InvalidUIDLSecurityKeyException {
/*
* URI pattern: APP/UPLOAD/[PID]/[NAME]/[SECKEY] See #createReceiverUrl
*/
- String pathInfo = request.getPathInfo();
+ String pathInfo = request.getRequestPathInfo();
// strip away part until the data we are interested starts
int startOfData = pathInfo
.indexOf(AbstractApplicationServlet.UPLOAD_URL_PREFIX)
@@ -240,20 +94,16 @@ public class CommunicationManager extends AbstractCommunicationManager {
VariableOwner source = getVariableOwner(paintableId);
String contentType = request.getContentType();
- if (request.getContentType().contains("boundary")) {
+ if (contentType.contains("boundary")) {
// Multipart requests contain boundary string
- doHandleSimpleMultipartFileUpload(
- new HttpServletRequestWrapper(request),
- new HttpServletResponseWrapper(response),
+ doHandleSimpleMultipartFileUpload(request, response,
streamVariable, variableName, source,
contentType.split("boundary=")[1]);
} else {
// if boundary string does not exist, the posted file is from
// XHR2.post(File)
- doHandleXhrFilePost(new HttpServletRequestWrapper(request),
- new HttpServletResponseWrapper(response),
- streamVariable, variableName, source,
- request.getContentLength());
+ doHandleXhrFilePost(request, response, streamVariable,
+ variableName, source, request.getContentLength());
}
} else {
throw new InvalidUIDLSecurityKeyException(
@@ -262,82 +112,6 @@ public class CommunicationManager extends AbstractCommunicationManager {
}
- /**
- * Handles UIDL request
- *
- * TODO document
- *
- * @param request
- * @param response
- * @param applicationServlet
- * @param window
- * target window of the UIDL request, can be null if window not
- * found
- * @throws IOException
- * @throws ServletException
- */
- public void handleUidlRequest(HttpServletRequest request,
- HttpServletResponse response,
- AbstractApplicationServlet applicationServlet, Window window)
- throws IOException, ServletException,
- InvalidUIDLSecurityKeyException {
- doHandleUidlRequest(new HttpServletRequestWrapper(request),
- new HttpServletResponseWrapper(response),
- new AbstractApplicationServletWrapper(applicationServlet),
- window);
- }
-
- /**
- * Gets the existing application or creates a new one. Get a window within
- * an application based on the requested URI.
- *
- * @param request
- * the HTTP Request.
- * @param application
- * the Application to query for window.
- * @param assumedWindow
- * if the window has been already resolved once, this parameter
- * must contain the window.
- * @return Window matching the given URI or null if not found.
- * @throws ServletException
- * if an exception has occurred that interferes with the
- * servlet's normal operation.
- */
- Window getApplicationWindow(HttpServletRequest request,
- AbstractApplicationServlet applicationServlet,
- Application application, Window assumedWindow)
- throws ServletException {
- return doGetApplicationWindow(new HttpServletRequestWrapper(request),
- new AbstractApplicationServletWrapper(applicationServlet),
- application, assumedWindow);
- }
-
- /**
- * Calls the Window URI handler for a request and returns the
- * {@link DownloadStream} returned by the handler.
- *
- * If the window is the main window of an application, the deprecated
- * {@link Application#handleURI(java.net.URL, String)} is called first to
- * handle {@link ApplicationResource}s and the window handler is only called
- * if it returns null.
- *
- * @see AbstractCommunicationManager#handleURI(Window, Request, Response,
- * Callback)
- *
- * @param window
- * @param request
- * @param response
- * @param applicationServlet
- * @return
- */
- DownloadStream handleURI(Window window, HttpServletRequest request,
- HttpServletResponse response,
- AbstractApplicationServlet applicationServlet) {
- return handleURI(window, new HttpServletRequestWrapper(request),
- new HttpServletResponseWrapper(response),
- new AbstractApplicationServletWrapper(applicationServlet));
- }
-
@Override
protected void unregisterPaintable(Component p) {
/* Cleanup possible receivers */
@@ -411,4 +185,72 @@ public class CommunicationManager extends AbstractCommunicationManager {
}
}
+ @Override
+ protected BootstrapHandler createBootstrapHandler() {
+ return new BootstrapHandler() {
+ @Override
+ protected String getApplicationId(BootstrapContext context) {
+ String appUrl = getAppUri(context);
+
+ String appId = appUrl;
+ if ("".equals(appUrl)) {
+ appId = "ROOT";
+ }
+ appId = appId.replaceAll("[^a-zA-Z0-9]", "");
+ // Add hashCode to the end, so that it is still (sort of)
+ // predictable, but indicates that it should not be used in CSS
+ // and
+ // such:
+ int hashCode = appId.hashCode();
+ if (hashCode < 0) {
+ hashCode = -hashCode;
+ }
+ appId = appId + "-" + hashCode;
+ return appId;
+ }
+
+ @Override
+ protected String getAppUri(BootstrapContext context) {
+ /* Fetch relative url to application */
+ // don't use server and port in uri. It may cause problems with
+ // some
+ // virtual server configurations which lose the server name
+ Application application = context.getApplication();
+ URL url = application.getURL();
+ String appUrl = url.getPath();
+ if (appUrl.endsWith("/")) {
+ appUrl = appUrl.substring(0, appUrl.length() - 1);
+ }
+ return appUrl;
+ }
+
+ @Override
+ public String getThemeName(BootstrapContext context) {
+ String themeName = context.getRequest().getParameter(
+ AbstractApplicationServlet.URL_PARAMETER_THEME);
+ if (themeName == null) {
+ themeName = super.getThemeName(context);
+ }
+ return themeName;
+ }
+
+ @Override
+ protected String getInitialUIDL(WrappedRequest request, Root root)
+ throws PaintException {
+ return CommunicationManager.this.getInitialUIDL(request, root);
+ }
+ };
+ }
+
+ @Override
+ protected InputStream getThemeResourceAsStream(Root root, String themeName,
+ String resource) {
+ WebApplicationContext context = (WebApplicationContext) root
+ .getApplication().getContext();
+ ServletContext servletContext = context.getHttpSession()
+ .getServletContext();
+ return servletContext.getResourceAsStream("/"
+ + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName
+ + "/" + resource);
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java b/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java
index 7889968e63..d3095512bb 100644
--- a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java
+++ b/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java
@@ -16,8 +16,9 @@ import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
-import com.vaadin.terminal.Sizeable;
+import com.vaadin.terminal.Sizeable.Unit;
import com.vaadin.ui.AbstractOrderedLayout;
+import com.vaadin.ui.AbstractSplitPanel;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.CustomComponent;
@@ -25,9 +26,7 @@ import com.vaadin.ui.Form;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.GridLayout.Area;
import com.vaadin.ui.Layout;
-import com.vaadin.ui.OrderedLayout;
import com.vaadin.ui.Panel;
-import com.vaadin.ui.SplitPanel;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
@@ -198,11 +197,7 @@ public class ComponentSizeValidator implements Serializable {
AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
boolean vertical = false;
- if (ol instanceof OrderedLayout) {
- if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
- vertical = true;
- }
- } else if (ol instanceof VerticalLayout) {
+ if (ol instanceof VerticalLayout) {
vertical = true;
}
@@ -231,11 +226,7 @@ public class ComponentSizeValidator implements Serializable {
AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
boolean horizontal = true;
- if (ol instanceof OrderedLayout) {
- if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
- horizontal = false;
- }
- } else if (ol instanceof VerticalLayout) {
+ if (ol instanceof VerticalLayout) {
horizontal = false;
}
@@ -323,7 +314,7 @@ public class ComponentSizeValidator implements Serializable {
width += "MAIN WINDOW";
} else if (component.getWidth() >= 0) {
width += "ABSOLUTE, " + component.getWidth() + " "
- + Sizeable.UNIT_SYMBOLS[component.getWidthUnits()];
+ + component.getWidthUnits().getSymbol();
} else {
width += "UNDEFINED";
}
@@ -339,7 +330,7 @@ public class ComponentSizeValidator implements Serializable {
height += "MAIN WINDOW";
} else if (component.getHeight() > 0) {
height += "ABSOLUTE, " + component.getHeight() + " "
- + Sizeable.UNIT_SYMBOLS[component.getHeightUnits()];
+ + component.getHeightUnits().getSymbol();
} else {
height += "UNDEFINED";
}
@@ -426,9 +417,7 @@ public class ComponentSizeValidator implements Serializable {
if (parent instanceof AbstractOrderedLayout) {
boolean horizontal = true;
- if (parent instanceof OrderedLayout) {
- horizontal = ((OrderedLayout) parent).getOrientation() == OrderedLayout.ORIENTATION_HORIZONTAL;
- } else if (parent instanceof VerticalLayout) {
+ if (parent instanceof VerticalLayout) {
horizontal = false;
}
if (horizontal
@@ -460,7 +449,7 @@ public class ComponentSizeValidator implements Serializable {
}
}
- if (parent instanceof Panel || parent instanceof SplitPanel
+ if (parent instanceof Panel || parent instanceof AbstractSplitPanel
|| parent instanceof TabSheet
|| parent instanceof CustomComponent) {
// height undefined, we know how how component works and no
@@ -488,7 +477,7 @@ public class ComponentSizeValidator implements Serializable {
}
private static boolean hasRelativeHeight(Component component) {
- return (component.getHeightUnits() == Sizeable.UNITS_PERCENTAGE && component
+ return (component.getHeightUnits() == Unit.PERCENTAGE && component
.getHeight() > 0);
}
@@ -504,7 +493,7 @@ public class ComponentSizeValidator implements Serializable {
private static boolean hasRelativeWidth(Component paintable) {
return paintable.getWidth() > 0
- && paintable.getWidthUnits() == Sizeable.UNITS_PERCENTAGE;
+ && paintable.getWidthUnits() == Unit.PERCENTAGE;
}
public static boolean parentCanDefineWidth(Component component) {
@@ -528,11 +517,7 @@ public class ComponentSizeValidator implements Serializable {
if (parent instanceof AbstractOrderedLayout) {
AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
boolean horizontal = true;
- if (ol instanceof OrderedLayout) {
- if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
- horizontal = false;
- }
- } else if (ol instanceof VerticalLayout) {
+ if (ol instanceof VerticalLayout) {
horizontal = false;
}
@@ -567,7 +552,7 @@ public class ComponentSizeValidator implements Serializable {
* the component width
*/
return hasNonRelativeWidthComponent((Form) parent);
- } else if (parent instanceof SplitPanel
+ } else if (parent instanceof AbstractSplitPanel
|| parent instanceof TabSheet
|| parent instanceof CustomComponent) {
// FIXME Could we use com.vaadin package name here and
diff --git a/src/com/vaadin/terminal/gwt/server/Constants.java b/src/com/vaadin/terminal/gwt/server/Constants.java
index e243bd7dae..7c467aa7f4 100644
--- a/src/com/vaadin/terminal/gwt/server/Constants.java
+++ b/src/com/vaadin/terminal/gwt/server/Constants.java
@@ -43,7 +43,6 @@ public interface Constants {
static final String URL_PARAMETER_REPAINT_ALL = "repaintAll";
static final String URL_PARAMETER_THEME = "theme";
- static final String SERVLET_PARAMETER_DEBUG = "Debug";
static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode";
static final String SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION = "disable-xsrf-protection";
static final String SERVLET_PARAMETER_RESOURCE_CACHE_TIME = "resourceCacheTime";
diff --git a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
index d6c53a2da6..91c15df5b2 100644
--- a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
+++ b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
@@ -37,6 +37,7 @@ import com.vaadin.ui.Alignment;
import com.vaadin.ui.ClientWidget;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomLayout;
+import com.vaadin.ui.Root;
/**
* User Interface Description Language Target.
@@ -1038,6 +1039,9 @@ public class JsonPaintTarget implements PaintTarget {
}
private boolean hasClientWidgetMapping(Class<? extends Paintable> class1) {
+ if (Root.class == class1) {
+ return true;
+ }
try {
return class1.isAnnotationPresent(ClientWidget.class);
} catch (NoClassDefFoundError e) {
diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java
deleted file mode 100644
index 362fee1cc7..0000000000
--- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-/**
- *
- */
-package com.vaadin.terminal.gwt.server;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.portlet.ActionRequest;
-import javax.portlet.ActionResponse;
-import javax.portlet.Portlet;
-import javax.portlet.PortletSession;
-import javax.portlet.RenderRequest;
-import javax.portlet.RenderResponse;
-import javax.servlet.http.HttpSession;
-
-import com.vaadin.Application;
-
-/**
- * @author marc
- */
-public class PortletApplicationContext extends WebApplicationContext implements
- Serializable {
-
- protected transient PortletSession portletSession;
-
- protected Map<Application, Set<PortletListener>> portletListeners = new HashMap<Application, Set<PortletListener>>();
-
- protected Map<Portlet, Application> portletToApplication = new HashMap<Portlet, Application>();
-
- PortletApplicationContext() {
-
- }
-
- static public PortletApplicationContext getApplicationContext(
- PortletSession session) {
- WebApplicationContext cx = (WebApplicationContext) session
- .getAttribute(WebApplicationContext.class.getName(),
- PortletSession.APPLICATION_SCOPE);
- if (cx == null) {
- cx = new PortletApplicationContext();
- }
- if (!(cx instanceof PortletApplicationContext)) {
- // TODO Should we even try this? And should we leave original as-is?
- PortletApplicationContext pcx = new PortletApplicationContext();
- pcx.applications.addAll(cx.applications);
- cx.applications.clear();
- pcx.browser = cx.browser;
- cx.browser = null;
- pcx.listeners = cx.listeners;
- cx.listeners = null;
- pcx.session = cx.session;
- cx = pcx;
- }
- if (((PortletApplicationContext) cx).portletSession == null) {
- ((PortletApplicationContext) cx).portletSession = session;
- }
- session.setAttribute(WebApplicationContext.class.getName(), cx,
- PortletSession.APPLICATION_SCOPE);
- return (PortletApplicationContext) cx;
- }
-
- static public WebApplicationContext getApplicationContext(
- HttpSession session) {
- WebApplicationContext cx = (WebApplicationContext) session
- .getAttribute(WebApplicationContext.class.getName());
- if (cx == null) {
- cx = new PortletApplicationContext();
- }
- if (cx.session == null) {
- cx.session = session;
- }
- session.setAttribute(WebApplicationContext.class.getName(), cx);
- return cx;
- }
-
- @Override
- protected void removeApplication(Application application) {
- portletListeners.remove(application);
- for (Iterator<Application> it = portletToApplication.values()
- .iterator(); it.hasNext();) {
- Application value = it.next();
- if (value == application) {
- // values().iterator() is backed by the map
- it.remove();
- }
- }
- super.removeApplication(application);
- }
-
- /**
- * Reinitializing the session is not supported from portlets.
- *
- * @see com.vaadin.terminal.gwt.server.WebApplicationContext#reinitializeSession()
- */
- @Override
- public void reinitializeSession() {
- throw new UnsupportedOperationException(
- "Reinitializing the session is not supported from portlets");
- }
-
- public void setPortletApplication(Portlet portlet, Application app) {
- portletToApplication.put(portlet, app);
- }
-
- public Application getPortletApplication(Portlet portlet) {
- return portletToApplication.get(portlet);
- }
-
- public PortletSession getPortletSession() {
- return portletSession;
- }
-
- public void addPortletListener(Application app, PortletListener listener) {
- Set<PortletListener> l = portletListeners.get(app);
- if (l == null) {
- l = new LinkedHashSet<PortletListener>();
- portletListeners.put(app, l);
- }
- l.add(listener);
- }
-
- public void removePortletListener(Application app, PortletListener listener) {
- Set<PortletListener> l = portletListeners.get(app);
- if (l != null) {
- l.remove(listener);
- }
- }
-
- public static void dispatchRequest(Portlet portlet, RenderRequest request,
- RenderResponse response) {
- PortletApplicationContext ctx = getApplicationContext(request
- .getPortletSession());
- if (ctx != null) {
- ctx.firePortletRenderRequest(portlet, request, response);
- }
- }
-
- public static void dispatchRequest(Portlet portlet, ActionRequest request,
- ActionResponse response) {
- PortletApplicationContext ctx = getApplicationContext(request
- .getPortletSession());
- if (ctx != null) {
- ctx.firePortletActionRequest(portlet, request, response);
- }
- }
-
- public void firePortletRenderRequest(Portlet portlet,
- RenderRequest request, RenderResponse response) {
- Application app = getPortletApplication(portlet);
- Set<PortletListener> listeners = portletListeners.get(app);
- if (listeners != null) {
- for (PortletListener l : listeners) {
- l.handleRenderRequest(request, new RestrictedRenderResponse(
- response));
- }
- }
- }
-
- public void firePortletActionRequest(Portlet portlet,
- ActionRequest request, ActionResponse response) {
- Application app = getPortletApplication(portlet);
- Set<PortletListener> listeners = portletListeners.get(app);
- if (listeners != null) {
- for (PortletListener l : listeners) {
- l.handleActionRequest(request, response);
- }
- }
- }
-
- public interface PortletListener extends Serializable {
- public void handleRenderRequest(RenderRequest request,
- RenderResponse response);
-
- public void handleActionRequest(ActionRequest request,
- ActionResponse response);
- }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
index dce1a1a78c..661da57af6 100644
--- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
+++ b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
@@ -35,8 +35,7 @@ import javax.xml.namespace.QName;
import com.vaadin.Application;
import com.vaadin.terminal.ApplicationResource;
-import com.vaadin.terminal.ExternalResource;
-import com.vaadin.ui.Window;
+import com.vaadin.ui.Root;
/**
* TODO Write documentation, fix JavaDoc tags.
@@ -172,18 +171,18 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
}
}
- public void firePortletRenderRequest(Application app, Window window,
+ public void firePortletRenderRequest(Application app, Root root,
RenderRequest request, RenderResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
l.handleRenderRequest(request, new RestrictedRenderResponse(
- response), window);
+ response), root);
}
}
}
- public void firePortletActionRequest(Application app, Window window,
+ public void firePortletActionRequest(Application app, Root root,
ActionRequest request, ActionResponse response) {
String key = request.getParameter(ActionRequest.ACTION_NAME);
if (eventActionDestinationMap.containsKey(key)) {
@@ -205,28 +204,28 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleActionRequest(request, response, window);
+ l.handleActionRequest(request, response, root);
}
}
}
}
- public void firePortletEventRequest(Application app, Window window,
+ public void firePortletEventRequest(Application app, Root root,
EventRequest request, EventResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleEventRequest(request, response, window);
+ l.handleEventRequest(request, response, root);
}
}
}
- public void firePortletResourceRequest(Application app, Window window,
+ public void firePortletResourceRequest(Application app, Root root,
ResourceRequest request, ResourceResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleResourceRequest(request, response, window);
+ l.handleResourceRequest(request, response, root);
}
}
}
@@ -234,16 +233,16 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
public interface PortletListener extends Serializable {
public void handleRenderRequest(RenderRequest request,
- RenderResponse response, Window window);
+ RenderResponse response, Root root);
public void handleActionRequest(ActionRequest request,
- ActionResponse response, Window window);
+ ActionResponse response, Root root);
public void handleEventRequest(EventRequest request,
- EventResponse response, Window window);
+ EventResponse response, Root root);
public void handleResourceRequest(ResourceRequest request,
- ResourceResponse response, Window window);
+ ResourceResponse response, Root root);
}
/**
@@ -308,7 +307,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* Event names for events sent and received by a portlet need to be declared
* in portlet.xml .
*
- * @param window
+ * @param root
* a window in which a temporary action URL can be opened if
* necessary
* @param name
@@ -317,7 +316,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* event value object that is Serializable and, if appropriate,
* has a valid JAXB annotation
*/
- public void sendPortletEvent(Window window, QName name, Serializable value)
+ public void sendPortletEvent(Root root, QName name, Serializable value)
throws IllegalStateException {
if (response instanceof MimeResponse) {
String actionKey = "" + System.currentTimeMillis();
@@ -328,7 +327,9 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
if (actionUrl != null) {
eventActionDestinationMap.put(actionKey, name);
eventActionValueMap.put(actionKey, value);
- window.open(new ExternalResource(actionUrl.toString()));
+ throw new RuntimeException(
+ "Root.open has not yet been implemented");
+ // root.open(new ExternalResource(actionUrl.toString()));
} else {
// this should never happen as we already know the response is a
// MimeResponse
@@ -355,7 +356,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* Shared parameters set or read by a portlet need to be declared in
* portlet.xml .
*
- * @param window
+ * @param root
* a window in which a temporary action URL can be opened if
* necessary
* @param name
@@ -363,8 +364,8 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* @param value
* parameter value
*/
- public void setSharedRenderParameter(Window window, String name,
- String value) throws IllegalStateException {
+ public void setSharedRenderParameter(Root root, String name, String value)
+ throws IllegalStateException {
if (response instanceof MimeResponse) {
String actionKey = "" + System.currentTimeMillis();
while (sharedParameterActionNameMap.containsKey(actionKey)) {
@@ -374,7 +375,9 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
if (actionUrl != null) {
sharedParameterActionNameMap.put(actionKey, name);
sharedParameterActionValueMap.put(actionKey, value);
- window.open(new ExternalResource(actionUrl.toString()));
+ throw new RuntimeException(
+ "Root.open has not yet been implemented");
+ // root.open(new ExternalResource(actionUrl.toString()));
} else {
// this should never happen as we already know the response is a
// MimeResponse
@@ -394,7 +397,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
*
* Portlet modes used by a portlet need to be declared in portlet.xml .
*
- * @param window
+ * @param root
* a window in which the render URL can be opened if necessary
* @param portletMode
* the portlet mode to switch to
@@ -402,12 +405,13 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* if the portlet mode is not allowed for some reason
* (configuration, permissions etc.)
*/
- public void setPortletMode(Window window, PortletMode portletMode)
+ public void setPortletMode(Root root, PortletMode portletMode)
throws IllegalStateException, PortletModeException {
if (response instanceof MimeResponse) {
PortletURL url = ((MimeResponse) response).createRenderURL();
url.setPortletMode(portletMode);
- window.open(new ExternalResource(url.toString()));
+ throw new RuntimeException("Root.open has not yet been implemented");
+ // root.open(new ExternalResource(url.toString()));
} else if (response instanceof StateAwareResponse) {
((StateAwareResponse) response).setPortletMode(portletMode);
} else {
diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
index ffa8ad4054..49bcb7a79c 100644
--- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
@@ -5,29 +5,30 @@ package com.vaadin.terminal.gwt.server;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
-import javax.portlet.ClientDataRequest;
import javax.portlet.MimeResponse;
+import javax.portlet.PortletContext;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
-import javax.portlet.PortletSession;
-import javax.portlet.ResourceRequest;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
import javax.portlet.ResourceResponse;
import javax.portlet.ResourceURL;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequestWrapper;
import com.vaadin.Application;
-import com.vaadin.terminal.DownloadStream;
+import com.vaadin.external.json.JSONException;
+import com.vaadin.external.json.JSONObject;
+import com.vaadin.terminal.DeploymentConfiguration;
+import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.Paintable;
import com.vaadin.terminal.StreamVariable;
import com.vaadin.terminal.VariableOwner;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
import com.vaadin.ui.Component;
-import com.vaadin.ui.Window;
+import com.vaadin.ui.Root;
/**
* TODO document me!
@@ -40,160 +41,12 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
private transient ResourceResponse currentUidlResponse;
- private static class PortletRequestWrapper implements Request {
-
- private final PortletRequest request;
-
- public PortletRequestWrapper(PortletRequest request) {
- this.request = request;
- }
-
- public Object getAttribute(String name) {
- return request.getAttribute(name);
- }
-
- public int getContentLength() {
- return ((ClientDataRequest) request).getContentLength();
- }
-
- public InputStream getInputStream() throws IOException {
- return ((ClientDataRequest) request).getPortletInputStream();
- }
-
- public String getParameter(String name) {
- String value = request.getParameter(name);
- if (value == null) {
- // for GateIn portlet container simple-portal
- try {
- Method getRealReq = request.getClass().getMethod(
- "getRealRequest");
- HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq
- .invoke(request);
- value = origRequest.getParameter(name);
- } catch (Exception e) {
- // do nothing - not on GateIn simple-portal
- }
- }
- return value;
- }
-
- public String getRequestID() {
- return "WindowID:" + request.getWindowID();
- }
-
- public Session getSession() {
- return new PortletSessionWrapper(request.getPortletSession());
- }
-
- public Object getWrappedRequest() {
- return request;
- }
-
- public boolean isRunningInPortlet() {
- return true;
- }
-
- public void setAttribute(String name, Object o) {
- request.setAttribute(name, o);
- }
-
- }
-
- private static class PortletResponseWrapper implements Response {
-
- private final PortletResponse response;
-
- public PortletResponseWrapper(PortletResponse response) {
- this.response = response;
- }
-
- public OutputStream getOutputStream() throws IOException {
- return ((MimeResponse) response).getPortletOutputStream();
- }
-
- public Object getWrappedResponse() {
- return response;
- }
-
- public void setContentType(String type) {
- ((MimeResponse) response).setContentType(type);
- }
- }
-
- private static class PortletSessionWrapper implements Session {
-
- private final PortletSession session;
-
- public PortletSessionWrapper(PortletSession session) {
- this.session = session;
- }
-
- public Object getAttribute(String name) {
- return session.getAttribute(name);
- }
-
- public int getMaxInactiveInterval() {
- return session.getMaxInactiveInterval();
- }
-
- public Object getWrappedSession() {
- return session;
- }
-
- public boolean isNew() {
- return session.isNew();
- }
-
- public void setAttribute(String name, Object o) {
- session.setAttribute(name, o);
- }
-
- }
-
- private static class AbstractApplicationPortletWrapper implements Callback {
-
- private final AbstractApplicationPortlet portlet;
-
- public AbstractApplicationPortletWrapper(
- AbstractApplicationPortlet portlet) {
- this.portlet = portlet;
- }
-
- public void criticalNotification(Request request, Response response,
- String cap, String msg, String details, String outOfSyncURL)
- throws IOException {
- portlet.criticalNotification(
- (PortletRequest) request.getWrappedRequest(),
- (MimeResponse) response.getWrappedResponse(), cap, msg,
- details, outOfSyncURL);
- }
-
- public String getRequestPathInfo(Request request) {
- if (request.getWrappedRequest() instanceof ResourceRequest) {
- return ((ResourceRequest) request.getWrappedRequest())
- .getResourceID();
- } else {
- // We do not use paths in portlet mode
- throw new UnsupportedOperationException(
- "PathInfo only available when using ResourceRequests");
- }
- }
-
- public InputStream getThemeResourceAsStream(String themeName,
- String resource) throws IOException {
- return portlet.getPortletContext().getResourceAsStream(
- "/" + AbstractApplicationPortlet.THEME_DIRECTORY_PATH
- + themeName + "/" + resource);
- }
-
- }
-
public PortletCommunicationManager(Application application) {
super(application);
}
- public void handleFileUpload(ResourceRequest request,
- ResourceResponse response) throws IOException {
+ public void handleFileUpload(WrappedRequest request,
+ WrappedResponse response) throws IOException {
String contentType = request.getContentType();
String name = request.getParameter("name");
String ownerId = request.getParameter("rec-owner");
@@ -202,13 +55,11 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
variableOwner).get(name);
if (contentType.contains("boundary")) {
- doHandleSimpleMultipartFileUpload(
- new PortletRequestWrapper(request),
- new PortletResponseWrapper(response), streamVariable, name,
- variableOwner, contentType.split("boundary=")[1]);
+ doHandleSimpleMultipartFileUpload(request, response,
+ streamVariable, name, variableOwner,
+ contentType.split("boundary=")[1]);
} else {
- doHandleXhrFilePost(new PortletRequestWrapper(request),
- new PortletResponseWrapper(response), streamVariable, name,
+ doHandleXhrFilePost(request, response, streamVariable, name,
variableOwner, request.getContentLength());
}
@@ -222,52 +73,16 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
}
}
- public void handleUidlRequest(ResourceRequest request,
- ResourceResponse response,
- AbstractApplicationPortlet applicationPortlet, Window window)
- throws InvalidUIDLSecurityKeyException, IOException {
- currentUidlResponse = response;
- doHandleUidlRequest(new PortletRequestWrapper(request),
- new PortletResponseWrapper(response),
- new AbstractApplicationPortletWrapper(applicationPortlet),
- window);
+ @Override
+ public void handleUidlRequest(WrappedRequest request,
+ WrappedResponse response, Callback callback, Root root)
+ throws IOException, InvalidUIDLSecurityKeyException {
+ currentUidlResponse = (ResourceResponse) ((WrappedPortletResponse) response)
+ .getPortletResponse();
+ super.handleUidlRequest(request, response, callback, root);
currentUidlResponse = null;
}
- DownloadStream handleURI(Window window, ResourceRequest request,
- ResourceResponse response,
- AbstractApplicationPortlet applicationPortlet) {
- return handleURI(window, new PortletRequestWrapper(request),
- new PortletResponseWrapper(response),
- new AbstractApplicationPortletWrapper(applicationPortlet));
- }
-
- /**
- * Gets the existing application or creates a new one. Get a window within
- * an application based on the requested URI.
- *
- * @param request
- * the portlet Request.
- * @param applicationPortlet
- * @param application
- * the Application to query for window.
- * @param assumedWindow
- * if the window has been already resolved once, this parameter
- * must contain the window.
- * @return Window matching the given URI or null if not found.
- * @throws ServletException
- * if an exception has occurred that interferes with the
- * servlet's normal operation.
- */
- Window getApplicationWindow(PortletRequest request,
- AbstractApplicationPortlet applicationPortlet,
- Application application, Window assumedWindow) {
-
- return doGetApplicationWindow(new PortletRequestWrapper(request),
- new AbstractApplicationPortletWrapper(applicationPortlet),
- application, assumedWindow);
- }
-
private Map<VariableOwner, Map<String, StreamVariable>> ownerToNameToStreamVariable;
@Override
@@ -302,4 +117,131 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
}
}
+ @Override
+ protected BootstrapHandler createBootstrapHandler() {
+ return new BootstrapHandler() {
+ @Override
+ public boolean handleRequest(Application application,
+ WrappedRequest request, WrappedResponse response)
+ throws IOException {
+ PortletRequest portletRequest = WrappedPortletRequest.cast(
+ request).getPortletRequest();
+ if (portletRequest instanceof RenderRequest) {
+ return super.handleRequest(application, request, response);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected String getApplicationId(BootstrapContext context) {
+ PortletRequest portletRequest = WrappedPortletRequest.cast(
+ context.getRequest()).getPortletRequest();
+ /*
+ * We need to generate a unique ID because some portals already
+ * create a DIV with the portlet's Window ID as the DOM ID.
+ */
+ return "v-" + portletRequest.getWindowID();
+ }
+
+ @Override
+ protected String getAppUri(BootstrapContext context) {
+ return getRenderResponse(context).createActionURL().toString();
+ }
+
+ private RenderResponse getRenderResponse(BootstrapContext context) {
+ PortletResponse response = ((WrappedPortletResponse) context
+ .getResponse()).getPortletResponse();
+
+ RenderResponse renderResponse = (RenderResponse) response;
+ return renderResponse;
+ }
+
+ @Override
+ protected JSONObject getDefaultParameters(BootstrapContext context)
+ throws JSONException {
+ /*
+ * We need this in order to get uploads to work. TODO this is
+ * not needed for uploads anymore, check if this is needed for
+ * some other things
+ */
+ JSONObject defaults = super.getDefaultParameters(context);
+ defaults.put("usePortletURLs", true);
+
+ ResourceURL uidlUrlBase = getRenderResponse(context)
+ .createResourceURL();
+ uidlUrlBase.setResourceID("UIDL");
+ defaults.put("portletUidlURLBase", uidlUrlBase.toString());
+ defaults.put("pathInfo", "");
+
+ return defaults;
+ }
+
+ @Override
+ protected void writeMainScriptTagContents(BootstrapContext context)
+ throws JSONException, IOException {
+ // fixed base theme to use - all portal pages with Vaadin
+ // applications will load this exactly once
+ String portalTheme = WrappedPortletRequest
+ .cast(context.getRequest())
+ .getPortalProperty(
+ AbstractApplicationPortlet.PORTAL_PARAMETER_VAADIN_THEME);
+ if (portalTheme != null
+ && !portalTheme.equals(context.getThemeName())) {
+ String portalThemeUri = getThemeUri(context, portalTheme);
+ // XSS safe - originates from portal properties
+ context.getWriter().write(
+ "vaadin.loadTheme('" + portalThemeUri + "');");
+ }
+
+ super.writeMainScriptTagContents(context);
+ }
+
+ @Override
+ protected String getMainDivStyle(BootstrapContext context) {
+ DeploymentConfiguration deploymentConfiguration = context
+ .getRequest().getDeploymentConfiguration();
+ return deploymentConfiguration.getApplicationOrSystemProperty(
+ AbstractApplicationPortlet.PORTLET_PARAMETER_STYLE,
+ null);
+ }
+
+ @Override
+ protected String getInitialUIDL(WrappedRequest request, Root root)
+ throws PaintException {
+ return PortletCommunicationManager.this.getInitialUIDL(request,
+ root);
+ }
+
+ @Override
+ protected JSONObject getApplicationParameters(
+ BootstrapContext context) throws JSONException,
+ PaintException {
+ JSONObject parameters = super.getApplicationParameters(context);
+ WrappedPortletResponse wrappedPortletResponse = (WrappedPortletResponse) context
+ .getResponse();
+ MimeResponse portletResponse = (MimeResponse) wrappedPortletResponse
+ .getPortletResponse();
+ ResourceURL resourceURL = portletResponse.createResourceURL();
+ resourceURL.setResourceID("browserDetails");
+ parameters.put("browserDetailsUrl", resourceURL.toString());
+ return parameters;
+ }
+
+ };
+
+ }
+
+ @Override
+ protected InputStream getThemeResourceAsStream(Root root, String themeName,
+ String resource) {
+ PortletApplicationContext2 context = (PortletApplicationContext2) root
+ .getApplication().getContext();
+ PortletContext portletContext = context.getPortletSession()
+ .getPortletContext();
+ return portletContext.getResourceAsStream("/"
+ + AbstractApplicationPortlet.THEME_DIRECTORY_PATH + themeName
+ + "/" + resource);
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
new file mode 100644
index 0000000000..9b1e60e621
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
@@ -0,0 +1,73 @@
+package com.vaadin.terminal.gwt.server;
+
+import java.io.Serializable;
+
+import com.vaadin.Application;
+import com.vaadin.ui.Root;
+
+/*
+ @VaadinApache2LicenseForJavaFiles@
+ */
+
+class ServletPortletHelper implements Serializable {
+ public static class ApplicationClassException extends Exception {
+
+ public ApplicationClassException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ApplicationClassException(String message) {
+ super(message);
+ }
+ }
+
+ static Class<? extends Application> getApplicationClass(
+ String applicationParameter, String rootParameter,
+ ClassLoader classLoader) throws ApplicationClassException {
+ if (applicationParameter == null) {
+
+ // Validate the parameter value
+ verifyRootClass(rootParameter, classLoader);
+
+ // Application can be used if a valid rootLayout is defined
+ return Application.class;
+ }
+
+ try {
+ return (Class<? extends Application>) classLoader
+ .loadClass(applicationParameter);
+ } catch (final ClassNotFoundException e) {
+ throw new ApplicationClassException(
+ "Failed to load application class: " + applicationParameter,
+ e);
+ }
+ }
+
+ private static void verifyRootClass(String className,
+ ClassLoader classLoader) throws ApplicationClassException {
+ if (className == null) {
+ throw new ApplicationClassException(Application.ROOT_PARAMETER
+ + " init parameter not defined");
+ }
+
+ // Check that the root layout class can be found
+ try {
+ Class<?> rootClass = classLoader.loadClass(className);
+ if (!Root.class.isAssignableFrom(rootClass)) {
+ throw new ApplicationClassException(className
+ + " does not implement Root");
+ }
+ // Try finding a default constructor, else throw exception
+ rootClass.getConstructor();
+ } catch (ClassNotFoundException e) {
+ throw new ApplicationClassException(className
+ + " could not be loaded", e);
+ } catch (SecurityException e) {
+ throw new ApplicationClassException("Could not access " + className
+ + " class", e);
+ } catch (NoSuchMethodException e) {
+ throw new ApplicationClassException(className
+ + " doesn't have a public no-args constructor");
+ }
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java b/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java
new file mode 100644
index 0000000000..334a7acf8d
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java
@@ -0,0 +1,88 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.server;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.RequestHandler;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
+
+/**
+ * A {@link RequestHandler} that presents an informative page if the browser in
+ * use is unsupported. Recognizes Chrome Frame and allow it to be used.
+ *
+ * <p>
+ * This handler is usually added to the application by
+ * {@link AbstractCommunicationManager}.
+ * </p>
+ */
+@SuppressWarnings("serial")
+public class UnsupportedBrowserHandler implements RequestHandler {
+
+ /** Cookie used to ignore browser checks */
+ public static final String FORCE_LOAD_COOKIE = "vaadinforceload=1";
+
+ public boolean handleRequest(Application application,
+ WrappedRequest request, WrappedResponse response)
+ throws IOException {
+
+ if (request.getBrowserDetails() != null) {
+ // Check if the browser is supported
+ // If Chrome Frame is available we'll assume it's ok
+ WebBrowser b = request.getBrowserDetails().getWebBrowser();
+ if (b.isTooOldToFunctionProperly() && !b.isChromeFrameCapable()) {
+ // bypass if cookie set
+ String c = request.getHeader("Cookie");
+ if (c == null || !c.contains(FORCE_LOAD_COOKIE)) {
+ writeBrowserTooOldPage(request, response);
+ return true; // request handled
+ }
+ }
+ }
+
+ return false; // pass to next handler
+ }
+
+ /**
+ * Writes a page encouraging the user to upgrade to a more current browser.
+ *
+ * @param request
+ * @param response
+ * @throws IOException
+ */
+ protected void writeBrowserTooOldPage(WrappedRequest request,
+ WrappedResponse response) throws IOException {
+ Writer page = response.getWriter();
+ WebBrowser b = request.getBrowserDetails().getWebBrowser();
+
+ page.write("<html><body><h1>I'm sorry, but your browser is not supported</h1>"
+ + "<p>The version ("
+ + b.getBrowserMajorVersion()
+ + "."
+ + b.getBrowserMinorVersion()
+ + ") of the browser you are using "
+ + " is outdated and not supported.</p>"
+ + "<p>You should <b>consider upgrading</b> to a more up-to-date browser.</p> "
+ + "<p>The most popular browsers are <b>"
+ + " <a href=\"https://www.google.com/chrome\">Chrome</a>,"
+ + " <a href=\"http://www.mozilla.com/firefox\">Firefox</a>,"
+ + (b.isWindows() ? " <a href=\"http://windows.microsoft.com/en-US/internet-explorer/downloads/ie\">Internet Explorer</a>,"
+ : "")
+ + " <a href=\"http://www.opera.com/browser\">Opera</a>"
+ + " and <a href=\"http://www.apple.com/safari\">Safari</a>.</b><br/>"
+ + "Upgrading to the latest version of one of these <b>will make the web safer, faster and better looking.</b></p>"
+ + (b.isIE() ? "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js\"></script>"
+ + "<p>If you can not upgrade your browser, please consider trying <a onclick=\"CFInstall.check({mode:'overlay'});return false;\" href=\"http://www.google.com/chromeframe\">Chrome Frame</a>.</p>"
+ : "") //
+ + "<p><sub><a onclick=\"document.cookie='"
+ + FORCE_LOAD_COOKIE
+ + "';window.location.reload();return false;\" href=\"#\">Continue without updating</a> (not recommended)</sub></p>"
+ + "</body>\n" + "</html>");
+
+ page.close();
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/server/WebBrowser.java b/src/com/vaadin/terminal/gwt/server/WebBrowser.java
index a57a4c65d2..358f6f38fb 100644
--- a/src/com/vaadin/terminal/gwt/server/WebBrowser.java
+++ b/src/com/vaadin/terminal/gwt/server/WebBrowser.java
@@ -8,6 +8,7 @@ import java.util.Date;
import java.util.Locale;
import com.vaadin.terminal.Terminal;
+import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.gwt.client.VBrowserDetails;
/**
@@ -189,6 +190,34 @@ public class WebBrowser implements Terminal {
}
/**
+ * Tests whether the user is using Chrome Frame.
+ *
+ * @return true if the user is using Chrome Frame, false if the user is not
+ * using Chrome or if no information on the browser is present
+ */
+ public boolean isChromeFrame() {
+ if (browserDetails == null) {
+ return false;
+ }
+
+ return browserDetails.isChromeFrame();
+ }
+
+ /**
+ * Tests whether the user's browser is Chrome Frame capable.
+ *
+ * @return true if the user can use Chrome Frame, false if the user can not
+ * or if no information on the browser is present
+ */
+ public boolean isChromeFrameCapable() {
+ if (browserDetails == null) {
+ return false;
+ }
+
+ return browserDetails.isChromeFrameCapable();
+ }
+
+ /**
* Gets the major version of the browser the user is using.
*
* <p>
@@ -417,25 +446,50 @@ public class WebBrowser implements Terminal {
* only. Updates all properties in the class according to the given
* information.
*
- * @param locale
- * The browser primary locale
- * @param address
- * The browser ip address
- * @param secureConnection
- * true if using an https connection
- * @param agent
- * Raw userAgent string from the browser
+ * @param request
+ * the wrapped request to read the information from
*/
- void updateRequestDetails(Locale locale, String address,
- boolean secureConnection, String agent) {
- this.locale = locale;
- this.address = address;
- this.secureConnection = secureConnection;
+ void updateRequestDetails(WrappedRequest request) {
+ locale = request.getLocale();
+ address = request.getRemoteAddr();
+ secureConnection = request.isSecure();
+ String agent = request.getHeader("user-agent");
+
if (agent != null) {
browserApplication = agent;
browserDetails = new VBrowserDetails(agent);
}
+ if (request.getParameter("sw") != null) {
+ updateClientSideDetails(request.getParameter("sw"),
+ request.getParameter("sh"), request.getParameter("cw"),
+ request.getParameter("ch"), request.getParameter("tzo"),
+ request.getParameter("rtzo"), request.getParameter("dstd"),
+ request.getParameter("dston"),
+ request.getParameter("curdate"),
+ request.getParameter("td") != null);
+ }
+ }
+
+ /**
+ * Checks if the browser is so old that it simply won't work with a Vaadin
+ * application. Can be used to redirect to an alternative page, show
+ * alternative content or similar.
+ *
+ * When this method returns true chances are very high that the browser
+ * won't work and it does not make sense to direct the user to the Vaadin
+ * application.
+ *
+ * @return true if the browser won't work, false if not the browser is
+ * supported or might work
+ */
+ public boolean isTooOldToFunctionProperly() {
+ if (browserDetails == null) {
+ // Don't know, so assume it will work
+ return false;
+ }
+
+ return browserDetails.isTooOldToFunctionProperly();
}
}
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java
new file mode 100644
index 0000000000..b6f1a192cb
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java
@@ -0,0 +1,109 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.CombinedRequest;
+import com.vaadin.terminal.DeploymentConfiguration;
+import com.vaadin.terminal.WrappedRequest;
+
+/**
+ * Wrapper for {@link HttpServletRequest}.
+ *
+ * @author Vaadin Ltd.
+ * @since 7.0
+ *
+ * @see WrappedRequest
+ * @see WrappedHttpServletResponse
+ */
+public class WrappedHttpServletRequest extends HttpServletRequestWrapper
+ implements WrappedRequest {
+
+ private final DeploymentConfiguration deploymentConfiguration;
+
+ /**
+ * Wraps a http servlet request and associates with a deployment
+ * configuration
+ *
+ * @param request
+ * the http servlet request to wrap
+ * @param deploymentConfiguration
+ * the associated deployment configuration
+ */
+ public WrappedHttpServletRequest(HttpServletRequest request,
+ DeploymentConfiguration deploymentConfiguration) {
+ super(request);
+ this.deploymentConfiguration = deploymentConfiguration;
+ }
+
+ public String getRequestPathInfo() {
+ return getPathInfo();
+ }
+
+ public int getSessionMaxInactiveInterval() {
+ return getSession().getMaxInactiveInterval();
+ }
+
+ public Object getSessionAttribute(String name) {
+ return getSession().getAttribute(name);
+ }
+
+ public void setSessionAttribute(String name, Object attribute) {
+ getSession().setAttribute(name, attribute);
+ }
+
+ /**
+ * Gets the original, unwrapped HTTP servlet request.
+ *
+ * @return the servlet request
+ */
+ public HttpServletRequest getHttpServletRequest() {
+ return this;
+ }
+
+ public DeploymentConfiguration getDeploymentConfiguration() {
+ return deploymentConfiguration;
+ }
+
+ public BrowserDetails getBrowserDetails() {
+ return new BrowserDetails() {
+ public String getUriFragment() {
+ return null;
+ }
+
+ public String getWindowName() {
+ return null;
+ }
+
+ public WebBrowser getWebBrowser() {
+ WebApplicationContext context = (WebApplicationContext) Application
+ .getCurrentApplication().getContext();
+ return context.getBrowser();
+ }
+ };
+ }
+
+ /**
+ * Helper method to get a <code>WrappedHttpServletRequest</code> from a
+ * <code>WrappedRequest</code>. Aside from casting, this method also takes
+ * care of situations where there's another level of wrapping.
+ *
+ * @param request
+ * a wrapped request
+ * @return a wrapped http servlet request
+ * @throws ClassCastException
+ * if the wrapped request doesn't wrap a http servlet request
+ */
+ public static WrappedHttpServletRequest cast(WrappedRequest request) {
+ if (request instanceof CombinedRequest) {
+ CombinedRequest combinedRequest = (CombinedRequest) request;
+ request = combinedRequest.getSecondRequest();
+ }
+ return (WrappedHttpServletRequest) request;
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java
new file mode 100644
index 0000000000..14a391b21f
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java
@@ -0,0 +1,73 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import com.vaadin.terminal.DeploymentConfiguration;
+import com.vaadin.terminal.WrappedResponse;
+
+/**
+ * Wrapper for {@link HttpServletResponse}.
+ *
+ * @author Vaadin Ltd.
+ * @since 7.0
+ *
+ * @see WrappedResponse
+ * @see WrappedHttpServletRequest
+ */
+public class WrappedHttpServletResponse extends HttpServletResponseWrapper
+ implements WrappedResponse {
+
+ private DeploymentConfiguration deploymentConfiguration;
+
+ /**
+ * Wraps a http servlet response and an associated deployment configuration
+ *
+ * @param response
+ * the http servlet response to wrap
+ * @param deploymentConfiguration
+ * the associated deployment configuration
+ */
+ public WrappedHttpServletResponse(HttpServletResponse response,
+ DeploymentConfiguration deploymentConfiguration) {
+ super(response);
+ this.deploymentConfiguration = deploymentConfiguration;
+ }
+
+ /**
+ * Gets the original unwrapped <code>HttpServletResponse</code>
+ *
+ * @return the unwrapped response
+ */
+ public HttpServletResponse getHttpServletResponse() {
+ return this;
+ }
+
+ public void setCacheTime(long milliseconds) {
+ doSetCacheTime(this, milliseconds);
+ }
+
+ // Implementation shared with WrappedPortletResponse
+ static void doSetCacheTime(WrappedResponse response, long milliseconds) {
+ if (milliseconds <= 0) {
+ response.setHeader("Cache-Control", "no-cache");
+ response.setHeader("Pragma", "no-cache");
+ response.setDateHeader("Expires", 0);
+ } else {
+ response.setHeader("Cache-Control", "max-age=" + milliseconds
+ / 1000);
+ response.setDateHeader("Expires", System.currentTimeMillis()
+ + milliseconds);
+ // Required to apply caching in some Tomcats
+ response.setHeader("Pragma", "cache");
+ }
+ }
+
+ public DeploymentConfiguration getDeploymentConfiguration() {
+ return deploymentConfiguration;
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
new file mode 100644
index 0000000000..2c9828b66b
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
@@ -0,0 +1,175 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.portlet.ClientDataRequest;
+import javax.portlet.PortletRequest;
+import javax.portlet.ResourceRequest;
+
+import com.vaadin.terminal.CombinedRequest;
+import com.vaadin.terminal.DeploymentConfiguration;
+import com.vaadin.terminal.WrappedRequest;
+
+/**
+ * Wrapper for {@link PortletRequest} and its subclasses.
+ *
+ * @author Vaadin Ltd.
+ * @since 7.0
+ *
+ * @see WrappedRequest
+ * @see WrappedPortletResponse
+ */
+public class WrappedPortletRequest implements WrappedRequest {
+
+ private final PortletRequest request;
+ private final DeploymentConfiguration deploymentConfiguration;
+
+ /**
+ * Wraps a portlet request and an associated deployment configuration
+ *
+ * @param request
+ * the portlet request to wrap
+ * @param deploymentConfiguration
+ * the associated deployment configuration
+ */
+ public WrappedPortletRequest(PortletRequest request,
+ DeploymentConfiguration deploymentConfiguration) {
+ this.request = request;
+ this.deploymentConfiguration = deploymentConfiguration;
+ }
+
+ public Object getAttribute(String name) {
+ return request.getAttribute(name);
+ }
+
+ public int getContentLength() {
+ try {
+ return ((ClientDataRequest) request).getContentLength();
+ } catch (ClassCastException e) {
+ throw new IllegalStateException(
+ "Content lenght only available for ClientDataRequests");
+ }
+ }
+
+ public InputStream getInputStream() throws IOException {
+ try {
+ return ((ClientDataRequest) request).getPortletInputStream();
+ } catch (ClassCastException e) {
+ throw new IllegalStateException(
+ "Input data only available for ClientDataRequests");
+ }
+ }
+
+ public String getParameter(String name) {
+ return request.getParameter(name);
+ }
+
+ public Map<String, String[]> getParameterMap() {
+ return request.getParameterMap();
+ }
+
+ public void setAttribute(String name, Object o) {
+ request.setAttribute(name, o);
+ }
+
+ public String getRequestPathInfo() {
+ if (request instanceof ResourceRequest) {
+ return ((ResourceRequest) request).getResourceID();
+ } else {
+ return null;
+ }
+ }
+
+ public int getSessionMaxInactiveInterval() {
+ return request.getPortletSession().getMaxInactiveInterval();
+ }
+
+ public Object getSessionAttribute(String name) {
+ return request.getPortletSession().getAttribute(name);
+ }
+
+ public void setSessionAttribute(String name, Object attribute) {
+ request.getPortletSession().setAttribute(name, attribute);
+ }
+
+ /**
+ * Gets the original, unwrapped portlet request.
+ *
+ * @return the unwrapped portlet request
+ */
+ public PortletRequest getPortletRequest() {
+ return request;
+ }
+
+ public String getContentType() {
+ try {
+ return ((ResourceRequest) request).getContentType();
+ } catch (ClassCastException e) {
+ throw new IllegalStateException(
+ "Content type only available for ResourceRequests");
+ }
+ }
+
+ public BrowserDetails getBrowserDetails() {
+ // No browserDetails available for normal requests
+ return null;
+ }
+
+ public Locale getLocale() {
+ return request.getLocale();
+ }
+
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ public boolean isSecure() {
+ return request.isSecure();
+ }
+
+ public String getHeader(String string) {
+ return null;
+ }
+
+ /**
+ * Reads a portal property from the portal context of the wrapped request.
+ *
+ * @param name
+ * a string with the name of the portal property to get
+ * @return a string with the value of the property, or <code>null</code> if
+ * the property is not defined
+ */
+ public String getPortalProperty(String name) {
+ return request.getPortalContext().getProperty(name);
+ }
+
+ public DeploymentConfiguration getDeploymentConfiguration() {
+ return deploymentConfiguration;
+ }
+
+ /**
+ * Helper method to get a <code>WrappedPortlettRequest</code> from a
+ * <code>WrappedRequest</code>. Aside from casting, this method also takes
+ * care of situations where there's another level of wrapping.
+ *
+ * @param request
+ * a wrapped request
+ * @return a wrapped portlet request
+ * @throws ClassCastException
+ * if the wrapped request doesn't wrap a portlet request
+ */
+ public static WrappedPortletRequest cast(WrappedRequest request) {
+ if (request instanceof CombinedRequest) {
+ CombinedRequest combinedRequest = (CombinedRequest) request;
+ request = combinedRequest.getSecondRequest();
+ }
+ return (WrappedPortletRequest) request;
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java
new file mode 100644
index 0000000000..8824396352
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java
@@ -0,0 +1,102 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.portlet.MimeResponse;
+import javax.portlet.PortletResponse;
+import javax.portlet.ResourceResponse;
+
+import com.vaadin.terminal.DeploymentConfiguration;
+import com.vaadin.terminal.WrappedResponse;
+
+/**
+ * Wrapper for {@link PortletResponse} and its subclasses.
+ *
+ * @author Vaadin Ltd.
+ * @since 7.0
+ *
+ * @see WrappedResponse
+ * @see WrappedPortletRequest
+ */
+public class WrappedPortletResponse implements WrappedResponse {
+ private static final DateFormat HTTP_DATE_FORMAT = new SimpleDateFormat(
+ "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
+ static {
+ HTTP_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+ private final PortletResponse response;
+ private DeploymentConfiguration deploymentConfiguration;
+
+ /**
+ * Wraps a portlet response and an associated deployment configuration
+ *
+ * @param response
+ * the portlet response to wrap
+ * @param deploymentConfiguration
+ * the associated deployment configuration
+ */
+ public WrappedPortletResponse(PortletResponse response,
+ DeploymentConfiguration deploymentConfiguration) {
+ this.response = response;
+ this.deploymentConfiguration = deploymentConfiguration;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return ((MimeResponse) response).getPortletOutputStream();
+ }
+
+ /**
+ * Gets the original, unwrapped portlet response.
+ *
+ * @return the unwrapped portlet response
+ */
+ public PortletResponse getPortletResponse() {
+ return response;
+ }
+
+ public void setContentType(String type) {
+ ((MimeResponse) response).setContentType(type);
+ }
+
+ public PrintWriter getWriter() throws IOException {
+ return ((MimeResponse) response).getWriter();
+ }
+
+ public void setStatus(int responseStatus) {
+ response.setProperty(ResourceResponse.HTTP_STATUS_CODE,
+ Integer.toString(responseStatus));
+ }
+
+ public void setHeader(String name, String value) {
+ response.setProperty(name, value);
+ }
+
+ public void setDateHeader(String name, long timestamp) {
+ response.setProperty(name, HTTP_DATE_FORMAT.format(new Date(timestamp)));
+ }
+
+ public void setCacheTime(long milliseconds) {
+ WrappedHttpServletResponse.doSetCacheTime(this, milliseconds);
+ }
+
+ public void sendError(int errorCode, String message) throws IOException {
+ setStatus(errorCode);
+ getWriter().write(message);
+ }
+
+ public DeploymentConfiguration getDeploymentConfiguration() {
+ return deploymentConfiguration;
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
index 2e4ce39513..ae744aa4f8 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
@@ -33,6 +33,7 @@ import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
import com.vaadin.event.dd.acceptcriteria.ClientCriterion;
import com.vaadin.terminal.Paintable;
import com.vaadin.ui.ClientWidget;
+import com.vaadin.ui.Root;
/**
* Utility class to collect widgetset related information from classpath.
@@ -95,7 +96,7 @@ public class ClassPathExplorer {
/**
* Finds server side widgets with {@link ClientWidget} annotation on the
* class path (entries that can contain widgets/widgetsets - see
- * {@link #getRawClasspathEntries()}).
+ * getRawClasspathEntries()).
*
* As a side effect, also accept criteria are searched under the same class
* path entries and added into the acceptCriterion collection.
@@ -563,7 +564,7 @@ public class ClassPathExplorer {
Class<?> c = Class.forName(fullclassName);
- if (c.getAnnotation(ClientWidget.class) != null) {
+ if (c.getAnnotation(ClientWidget.class) != null || Root.class == c) {
paintables.add((Class<? extends Paintable>) c);
// System.out.println("Found paintable " + fullclassName);
} else if (c.getAnnotation(ClientCriterion.class) != null) {
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java
index c1f9134e7b..2150748b54 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java
@@ -23,9 +23,11 @@ import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.terminal.Paintable;
-import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ui.VViewPaintable;
import com.vaadin.ui.ClientWidget;
import com.vaadin.ui.ClientWidget.LoadStyle;
+import com.vaadin.ui.Root;
/**
* WidgetMapGenerator's are GWT generator to build WidgetMapImpl dynamically
@@ -69,6 +71,8 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
*/
public class WidgetMapGenerator extends Generator {
+ private static String paintableClassName = VPaintableWidget.class.getName();
+
private String packageName;
private String className;
@@ -161,12 +165,10 @@ public class WidgetMapGenerator extends Generator {
.iterator(); iterator.hasNext();) {
Class<? extends Paintable> class1 = iterator.next();
- ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
-
- if (typeOracle.findType(annotation.value().getName()) == null) {
+ Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget> clientClass = getClientClass(class1);
+ if (typeOracle.findType(clientClass.getName()) == null) {
// GWT widget not inherited
- logger.log(Type.WARN, "Widget class "
- + annotation.value().getName()
+ logger.log(Type.WARN, "Widget class " + clientClass.getName()
+ " was not found. The component " + class1.getName()
+ " will not be included in the widgetset.");
iterator.remove();
@@ -225,6 +227,9 @@ public class WidgetMapGenerator extends Generator {
* the client side engine
*/
protected LoadStyle getLoadStyle(Class<? extends Paintable> paintableType) {
+ if (Root.class == paintableType) {
+ return LoadStyle.EAGER;
+ }
ClientWidget annotation = paintableType
.getAnnotation(ClientWidget.class);
return annotation.loadStyle();
@@ -239,23 +244,21 @@ public class WidgetMapGenerator extends Generator {
// TODO detect if it would be noticably faster to instantiate with a
// lookup with index than with the hashmap
- sourceWriter
- .println("public void ensureInstantiator(Class<? extends Paintable> classType) {");
+ sourceWriter.println("public void ensureInstantiator(Class<? extends "
+ + paintableClassName + "> classType) {");
sourceWriter.println("if(!instmap.containsKey(classType)){");
boolean first = true;
ArrayList<Class<? extends Paintable>> lazyLoadedWidgets = new ArrayList<Class<? extends Paintable>>();
-
- HashSet<Class<? extends com.vaadin.terminal.gwt.client.Paintable>> widgetsWithInstantiator = new HashSet<Class<? extends com.vaadin.terminal.gwt.client.Paintable>>();
-
+
+ HashSet<Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget>> widgetsWithInstantiator = new HashSet<Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget>>();
+
for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
- ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
- Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
- .value();
- if(widgetsWithInstantiator.contains(clientClass)) {
+ Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget> clientClass = getClientClass(class1);
+ if (widgetsWithInstantiator.contains(clientClass)) {
continue;
}
- if (clientClass == VView.class) {
+ if (clientClass == VViewPaintable.class) {
// VView's are not instantiated by widgetset
continue;
}
@@ -267,7 +270,8 @@ public class WidgetMapGenerator extends Generator {
sourceWriter.print("if( classType == " + clientClass.getName()
+ ".class) {");
- String instantiator = "new WidgetInstantiator() {\n public Paintable get() {\n return GWT.create("
+ String instantiator = "new WidgetInstantiator() {\n public "
+ + paintableClassName + " get() {\n return GWT.create("
+ clientClass.getName() + ".class );\n}\n}\n";
LoadStyle loadStyle = getLoadStyle(class1);
@@ -302,8 +306,8 @@ public class WidgetMapGenerator extends Generator {
sourceWriter.println("}");
- sourceWriter
- .println("public Class<? extends Paintable>[] getDeferredLoadedWidgets() {");
+ sourceWriter.println("public Class<? extends " + paintableClassName
+ + ">[] getDeferredLoadedWidgets() {");
sourceWriter.println("return new Class[] {");
first = true;
@@ -313,7 +317,7 @@ public class WidgetMapGenerator extends Generator {
}
first = false;
ClientWidget annotation = class2.getAnnotation(ClientWidget.class);
- Class<? extends com.vaadin.terminal.gwt.client.Paintable> value = annotation
+ Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget> value = annotation
.value();
sourceWriter.print(value.getName() + ".class");
}
@@ -328,11 +332,12 @@ public class WidgetMapGenerator extends Generator {
// TODO an index of last ensured widget in array
- sourceWriter
- .println("public Paintable instantiate(Class<? extends Paintable> classType) {");
+ sourceWriter.println("public " + paintableClassName
+ + " instantiate(Class<? extends " + paintableClassName
+ + "> classType) {");
sourceWriter.indent();
- sourceWriter
- .println("Paintable p = super.instantiate(classType); if(p!= null) return p;");
+ sourceWriter.println(paintableClassName
+ + " p = super.instantiate(classType); if(p!= null) return p;");
sourceWriter.println("return instmap.get(classType).get();");
sourceWriter.outdent();
@@ -350,16 +355,16 @@ public class WidgetMapGenerator extends Generator {
SourceWriter sourceWriter,
Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
sourceWriter
- .println("public Class<? extends Paintable> "
+ .println("public Class<? extends "
+ + paintableClassName
+ + "> "
+ "getImplementationByServerSideClassName(String fullyQualifiedName) {");
sourceWriter.indent();
sourceWriter
.println("fullyQualifiedName = fullyQualifiedName.intern();");
for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
- ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
- Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
- .value();
+ Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget> clientClass = getClientClass(class1);
sourceWriter.print("if ( fullyQualifiedName == \"");
sourceWriter.print(class1.getName());
sourceWriter.print("\" ) { ensureInstantiator("
@@ -369,9 +374,21 @@ public class WidgetMapGenerator extends Generator {
sourceWriter.print("else ");
}
sourceWriter
- .println("return com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class;");
+ .println("return com.vaadin.terminal.gwt.client.ui.VUnknownComponentPaintable.class;");
sourceWriter.outdent();
sourceWriter.println("}");
}
+
+ private static Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget> getClientClass(
+ Class<? extends Paintable> class1) {
+ Class<? extends com.vaadin.terminal.gwt.client.VPaintableWidget> clientClass;
+ if (Root.class == class1) {
+ clientClass = VViewPaintable.class;
+ } else {
+ ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
+ clientClass = annotation.value();
+ }
+ return clientClass;
+ }
}
diff --git a/src/com/vaadin/tools/ReflectTools.java b/src/com/vaadin/tools/ReflectTools.java
index 9f0667f90e..ea2afae301 100644
--- a/src/com/vaadin/tools/ReflectTools.java
+++ b/src/com/vaadin/tools/ReflectTools.java
@@ -3,6 +3,9 @@
*/
package com.vaadin.tools;
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
@@ -37,4 +40,87 @@ public class ReflectTools {
throw new ExceptionInInitializerError(e);
}
}
+
+ /**
+ * Returns the value of the java field.
+ * <p>
+ * Uses getter if present, otherwise tries to access even private fields
+ * directly.
+ *
+ * @param object
+ * The object containing the field
+ * @param field
+ * The field we want to get the value for
+ * @return The value of the field in the object
+ * @throws InvocationTargetException
+ * If the value could not be retrieved
+ * @throws IllegalAccessException
+ * If the value could not be retrieved
+ * @throws IllegalArgumentException
+ * If the value could not be retrieved
+ */
+ public static Object getJavaFieldValue(Object object,
+ java.lang.reflect.Field field) throws IllegalArgumentException,
+ IllegalAccessException, InvocationTargetException {
+ PropertyDescriptor pd;
+ try {
+ pd = new PropertyDescriptor(field.getName(), object.getClass());
+ Method getter = pd.getReadMethod();
+ if (getter != null) {
+ return getter.invoke(object, (Object[]) null);
+ }
+ } catch (IntrospectionException e1) {
+ // Ignore this and try to get directly using the field
+ }
+
+ // Try to get the value or throw an exception
+ if (!field.isAccessible()) {
+ // Try to gain access even if field is private
+ field.setAccessible(true);
+ }
+ return field.get(object);
+ }
+
+ /**
+ * Sets the value of a java field.
+ * <p>
+ * Uses setter if present, otherwise tries to access even private fields
+ * directly.
+ *
+ * @param object
+ * The object containing the field
+ * @param field
+ * The field we want to set the value for
+ * @param value
+ * The value to set
+ * @throws IllegalAccessException
+ * If the value could not be assigned to the field
+ * @throws IllegalArgumentException
+ * If the value could not be assigned to the field
+ * @throws InvocationTargetException
+ * If the value could not be assigned to the field
+ */
+ public static void setJavaFieldValue(Object object,
+ java.lang.reflect.Field field, Object value)
+ throws IllegalAccessException, IllegalArgumentException,
+ InvocationTargetException {
+ PropertyDescriptor pd;
+ try {
+ pd = new PropertyDescriptor(field.getName(), object.getClass());
+ Method setter = pd.getWriteMethod();
+ if (setter != null) {
+ // Exceptions are thrown forward if this fails
+ setter.invoke(object, value);
+ }
+ } catch (IntrospectionException e1) {
+ // Ignore this and try to set directly using the field
+ }
+
+ // Try to set the value directly to the field or throw an exception
+ if (!field.isAccessible()) {
+ // Try to gain access even if field is private
+ field.setAccessible(true);
+ }
+ field.set(object, value);
+ }
}
diff --git a/src/com/vaadin/ui/AbsoluteLayout.java b/src/com/vaadin/ui/AbsoluteLayout.java
index 7872e05774..c75073c02b 100644
--- a/src/com/vaadin/ui/AbsoluteLayout.java
+++ b/src/com/vaadin/ui/AbsoluteLayout.java
@@ -17,7 +17,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout;
+import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayoutPaintable;
/**
* AbsoluteLayout is a layout implementation that mimics html absolute
@@ -25,7 +25,7 @@ import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout;
*
*/
@SuppressWarnings("serial")
-@ClientWidget(VAbsoluteLayout.class)
+@ClientWidget(VAbsoluteLayoutPaintable.class)
public class AbsoluteLayout extends AbstractLayout implements
LayoutClickNotifier {
@@ -176,10 +176,10 @@ public class AbsoluteLayout extends AbstractLayout implements
private Float bottomValue = null;
private Float leftValue = null;
- private int topUnits;
- private int rightUnits;
- private int bottomUnits;
- private int leftUnits;
+ private Unit topUnits = Unit.PIXELS;
+ private Unit rightUnits = Unit.PIXELS;
+ private Unit bottomUnits = Unit.PIXELS;
+ private Unit leftUnits = Unit.PIXELS;
/**
* Sets the position attributes using CSS syntax. Attributes not
@@ -193,7 +193,7 @@ public class AbsoluteLayout extends AbstractLayout implements
*/
public void setCSSString(String css) {
topValue = rightValue = bottomValue = leftValue = null;
- topUnits = rightUnits = bottomUnits = leftUnits = 0;
+ topUnits = rightUnits = bottomUnits = leftUnits = Unit.PIXELS;
zIndex = -1;
if (css == null) {
return;
@@ -215,24 +215,25 @@ public class AbsoluteLayout extends AbstractLayout implements
} else {
value = "";
}
- String unit = value.replaceAll("[0-9\\.\\-]+", "");
- if (!unit.equals("")) {
- value = value.substring(0, value.indexOf(unit)).trim();
+ String symbol = value.replaceAll("[0-9\\.\\-]+", "");
+ if (!symbol.equals("")) {
+ value = value.substring(0, value.indexOf(symbol))
+ .trim();
}
float v = Float.parseFloat(value);
- int unitInt = parseCssUnit(unit);
+ Unit unit = Unit.getUnitFromSymbol(symbol);
if (key.equals("top")) {
topValue = v;
- topUnits = unitInt;
+ topUnits = unit;
} else if (key.equals("right")) {
rightValue = v;
- rightUnits = unitInt;
+ rightUnits = unit;
} else if (key.equals("bottom")) {
bottomValue = v;
- bottomUnits = unitInt;
+ bottomUnits = unit;
} else if (key.equals("left")) {
leftValue = v;
- leftUnits = unitInt;
+ leftUnits = unit;
}
}
}
@@ -240,23 +241,6 @@ public class AbsoluteLayout extends AbstractLayout implements
}
/**
- * Parses a string and checks if a unit is found. If a unit is not found
- * from the string the unit pixels is used.
- *
- * @param string
- * The string to parse the unit from
- * @return The found unit
- */
- private int parseCssUnit(String string) {
- for (int i = 0; i < UNIT_SYMBOLS.length; i++) {
- if (UNIT_SYMBOLS[i].equals(string)) {
- return i;
- }
- }
- return 0; // defaults to px (eg. top:0;)
- }
-
- /**
* Converts the internal values into a valid CSS string.
*
* @return A valid CSS string
@@ -264,16 +248,16 @@ public class AbsoluteLayout extends AbstractLayout implements
public String getCSSString() {
String s = "";
if (topValue != null) {
- s += "top:" + topValue + UNIT_SYMBOLS[topUnits] + ";";
+ s += "top:" + topValue + topUnits.getSymbol() + ";";
}
if (rightValue != null) {
- s += "right:" + rightValue + UNIT_SYMBOLS[rightUnits] + ";";
+ s += "right:" + rightValue + rightUnits.getSymbol() + ";";
}
if (bottomValue != null) {
- s += "bottom:" + bottomValue + UNIT_SYMBOLS[bottomUnits] + ";";
+ s += "bottom:" + bottomValue + bottomUnits.getSymbol() + ";";
}
if (leftValue != null) {
- s += "left:" + leftValue + UNIT_SYMBOLS[leftUnits] + ";";
+ s += "left:" + leftValue + leftUnits.getSymbol() + ";";
}
if (zIndex >= 0) {
s += "z-index:" + zIndex + ";";
@@ -291,7 +275,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* The unit of the 'top' attribute. See UNIT_SYMBOLS for a
* description of the available units.
*/
- public void setTop(Float topValue, int topUnits) {
+ public void setTop(Float topValue, Unit topUnits) {
this.topValue = topValue;
this.topUnits = topUnits;
requestRepaint();
@@ -307,7 +291,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* The unit of the 'right' attribute. See UNIT_SYMBOLS for a
* description of the available units.
*/
- public void setRight(Float rightValue, int rightUnits) {
+ public void setRight(Float rightValue, Unit rightUnits) {
this.rightValue = rightValue;
this.rightUnits = rightUnits;
requestRepaint();
@@ -323,7 +307,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* The unit of the 'bottom' attribute. See UNIT_SYMBOLS for a
* description of the available units.
*/
- public void setBottom(Float bottomValue, int bottomUnits) {
+ public void setBottom(Float bottomValue, Unit bottomUnits) {
this.bottomValue = bottomValue;
this.bottomUnits = bottomUnits;
requestRepaint();
@@ -339,7 +323,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* The unit of the 'left' attribute. See UNIT_SYMBOLS for a
* description of the available units.
*/
- public void setLeft(Float leftValue, int leftUnits) {
+ public void setLeft(Float leftValue, Unit leftUnits) {
this.leftValue = leftValue;
this.leftUnits = leftUnits;
requestRepaint();
@@ -456,7 +440,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public int getTopUnits() {
+ public Unit getTopUnits() {
return topUnits;
}
@@ -467,7 +451,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public void setTopUnits(int topUnits) {
+ public void setTopUnits(Unit topUnits) {
this.topUnits = topUnits;
requestRepaint();
}
@@ -478,7 +462,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public int getRightUnits() {
+ public Unit getRightUnits() {
return rightUnits;
}
@@ -489,7 +473,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public void setRightUnits(int rightUnits) {
+ public void setRightUnits(Unit rightUnits) {
this.rightUnits = rightUnits;
requestRepaint();
}
@@ -500,7 +484,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public int getBottomUnits() {
+ public Unit getBottomUnits() {
return bottomUnits;
}
@@ -511,7 +495,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public void setBottomUnits(int bottomUnits) {
+ public void setBottomUnits(Unit bottomUnits) {
this.bottomUnits = bottomUnits;
requestRepaint();
}
@@ -522,7 +506,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* @return See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public int getLeftUnits() {
+ public Unit getLeftUnits() {
return leftUnits;
}
@@ -533,7 +517,7 @@ public class AbsoluteLayout extends AbstractLayout implements
* See {@link Sizeable} UNIT_SYMBOLS for a description of the
* available units.
*/
- public void setLeftUnits(int leftUnits) {
+ public void setLeftUnits(Unit leftUnits) {
this.leftUnits = leftUnits;
requestRepaint();
}
diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java
index 0ca9cc6bd4..059076790b 100644
--- a/src/com/vaadin/ui/AbstractComponent.java
+++ b/src/com/vaadin/ui/AbstractComponent.java
@@ -19,8 +19,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.vaadin.Application;
+import com.vaadin.event.ActionManager;
import com.vaadin.event.EventRouter;
import com.vaadin.event.MethodEventSource;
+import com.vaadin.event.ShortcutListener;
import com.vaadin.terminal.ErrorMessage;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
@@ -138,13 +140,19 @@ public abstract class AbstractComponent implements Component, MethodEventSource
private float width = SIZE_UNDEFINED;
private float height = SIZE_UNDEFINED;
- private int widthUnit = UNITS_PIXELS;
- private int heightUnit = UNITS_PIXELS;
+ private Unit widthUnit = Unit.PIXELS;
+ private Unit heightUnit = Unit.PIXELS;
private static final Pattern sizePattern = Pattern
.compile("^(-?\\d+(\\.\\d+)?)(%|px|em|ex|in|cm|mm|pt|pc)?$");
private ComponentErrorHandler errorHandler = null;
+ /**
+ * Keeps track of the Actions added to this component; the actual
+ * handling/notifying is delegated, usually to the containing window.
+ */
+ private ActionManager actionManager;
+
/* Constructor */
/**
@@ -319,6 +327,8 @@ public abstract class AbstractComponent implements Component, MethodEventSource
*/
public void setLocale(Locale locale) {
this.locale = locale;
+
+ // FIXME: Reload value if there is a converter
requestRepaint();
}
@@ -609,11 +619,11 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* Gets the parent window of the component. Don't add a JavaDoc comment
* here, we use the default documentation from implemented interface.
*/
- public Window getWindow() {
+ public Root getRoot() {
if (parent == null) {
return null;
} else {
- return parent.getWindow();
+ return parent.getRoot();
}
}
@@ -635,6 +645,9 @@ public abstract class AbstractComponent implements Component, MethodEventSource
if (delayedFocus) {
focus();
}
+ if (actionManager != null) {
+ actionManager.setViewer(getRoot());
+ }
}
/*
@@ -642,6 +655,9 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* we use the default documentation from implemented interface.
*/
public void detach() {
+ if (actionManager != null) {
+ actionManager.setViewer((Root) null);
+ }
}
/**
@@ -651,7 +667,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
if (this instanceof Focusable) {
final Application app = getApplication();
if (app != null) {
- getWindow().setFocusedComponent((Focusable) this);
+ getRoot().setFocusedComponent((Focusable) this);
delayedFocus = false;
} else {
delayedFocus = true;
@@ -727,13 +743,13 @@ public abstract class AbstractComponent implements Component, MethodEventSource
// Only paint content of visible components.
if (isVisible()) {
if (getHeight() >= 0
- && (getHeightUnits() != UNITS_PERCENTAGE || ComponentSizeValidator
+ && (getHeightUnits() != Unit.PERCENTAGE || ComponentSizeValidator
.parentCanDefineHeight(this))) {
target.addAttribute("height", "" + getCSSHeight());
}
if (getWidth() >= 0
- && (getWidthUnits() != UNITS_PERCENTAGE || ComponentSizeValidator
+ && (getWidthUnits() != Unit.PERCENTAGE || ComponentSizeValidator
.parentCanDefineWidth(this))) {
target.addAttribute("width", "" + getCSSWidth());
}
@@ -791,10 +807,10 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* @return CSS height
*/
private String getCSSHeight() {
- if (getHeightUnits() == UNITS_PIXELS) {
- return ((int) getHeight()) + UNIT_SYMBOLS[getHeightUnits()];
+ if (getHeightUnits() == Unit.PIXELS) {
+ return ((int) getHeight()) + getHeightUnits().getSymbol();
} else {
- return getHeight() + UNIT_SYMBOLS[getHeightUnits()];
+ return getHeight() + getHeightUnits().getSymbol();
}
}
@@ -804,10 +820,10 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* @return CSS width
*/
private String getCSSWidth() {
- if (getWidthUnits() == UNITS_PIXELS) {
- return ((int) getWidth()) + UNIT_SYMBOLS[getWidthUnits()];
+ if (getWidthUnits() == Unit.PIXELS) {
+ return ((int) getWidth()) + getWidthUnits().getSymbol();
} else {
- return getWidth() + UNIT_SYMBOLS[getWidthUnits()];
+ return getWidth() + getWidthUnits().getSymbol();
}
}
@@ -1283,7 +1299,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
*
* @see com.vaadin.terminal.Sizeable#getHeightUnits()
*/
- public int getHeightUnits() {
+ public Unit getHeightUnits() {
return heightUnit;
}
@@ -1301,36 +1317,19 @@ public abstract class AbstractComponent implements Component, MethodEventSource
*
* @see com.vaadin.terminal.Sizeable#getWidthUnits()
*/
- public int getWidthUnits() {
+ public Unit getWidthUnits() {
return widthUnit;
}
/*
* (non-Javadoc)
*
- * @see com.vaadin.terminal.Sizeable#setHeight(float)
- */
- @Deprecated
- public void setHeight(float height) {
- setHeight(height, getHeightUnits());
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.terminal.Sizeable#setHeightUnits(int)
- */
- @Deprecated
- public void setHeightUnits(int unit) {
- setHeight(getHeight(), unit);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.terminal.Sizeable#setHeight(float, int)
+ * @see com.vaadin.terminal.Sizeable#setHeight(float, Unit)
*/
- public void setHeight(float height, int unit) {
+ public void setHeight(float height, Unit unit) {
+ if (unit == null) {
+ throw new IllegalArgumentException("Unit can not be null");
+ }
this.height = height;
heightUnit = unit;
requestRepaint();
@@ -1343,8 +1342,8 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* @see com.vaadin.terminal.Sizeable#setSizeFull()
*/
public void setSizeFull() {
- setWidth(100, UNITS_PERCENTAGE);
- setHeight(100, UNITS_PERCENTAGE);
+ setWidth(100, Unit.PERCENTAGE);
+ setHeight(100, Unit.PERCENTAGE);
}
/*
@@ -1353,36 +1352,19 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* @see com.vaadin.terminal.Sizeable#setSizeUndefined()
*/
public void setSizeUndefined() {
- setWidth(-1, UNITS_PIXELS);
- setHeight(-1, UNITS_PIXELS);
+ setWidth(-1, Unit.PIXELS);
+ setHeight(-1, Unit.PIXELS);
}
/*
* (non-Javadoc)
*
- * @see com.vaadin.terminal.Sizeable#setWidth(float)
+ * @see com.vaadin.terminal.Sizeable#setWidth(float, Unit)
*/
- @Deprecated
- public void setWidth(float width) {
- setWidth(width, getWidthUnits());
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.terminal.Sizeable#setWidthUnits(int)
- */
- @Deprecated
- public void setWidthUnits(int unit) {
- setWidth(getWidth(), unit);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.terminal.Sizeable#setWidth(float, int)
- */
- public void setWidth(float width, int unit) {
+ public void setWidth(float width, Unit unit) {
+ if (unit == null) {
+ throw new IllegalArgumentException("Unit can not be null");
+ }
this.width = width;
widthUnit = unit;
requestRepaint();
@@ -1395,8 +1377,12 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* @see com.vaadin.terminal.Sizeable#setWidth(java.lang.String)
*/
public void setWidth(String width) {
- float[] p = parseStringSize(width);
- setWidth(p[0], (int) p[1]);
+ Size size = parseStringSize(width);
+ if (size != null) {
+ setWidth(size.getSize(), size.getUnit());
+ } else {
+ setWidth(-1, Unit.PIXELS);
+ }
}
/*
@@ -1405,58 +1391,61 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* @see com.vaadin.terminal.Sizeable#setHeight(java.lang.String)
*/
public void setHeight(String height) {
- float[] p = parseStringSize(height);
- setHeight(p[0], (int) p[1]);
+ Size size = parseStringSize(height);
+ if (size != null) {
+ setHeight(size.getSize(), size.getUnit());
+ } else {
+ setHeight(-1, Unit.PIXELS);
+ }
}
/*
* Returns array with size in index 0 unit in index 1. Null or empty string
- * will produce {-1,UNITS_PIXELS}
+ * will produce {-1,Unit#PIXELS}
*/
- private static float[] parseStringSize(String s) {
- float[] values = { -1, UNITS_PIXELS };
+ private static Size parseStringSize(String s) {
if (s == null) {
- return values;
+ return null;
}
s = s.trim();
if ("".equals(s)) {
- return values;
+ return null;
}
-
+ float size = 0;
+ Unit unit = null;
Matcher matcher = sizePattern.matcher(s);
if (matcher.find()) {
- values[0] = Float.parseFloat(matcher.group(1));
- if (values[0] < 0) {
- values[0] = -1;
+ size = Float.parseFloat(matcher.group(1));
+ if (size < 0) {
+ size = -1;
+ unit = Unit.PIXELS;
} else {
- String unit = matcher.group(3);
- if (unit == null) {
- values[1] = UNITS_PIXELS;
- } else if (unit.equals("px")) {
- values[1] = UNITS_PIXELS;
- } else if (unit.equals("%")) {
- values[1] = UNITS_PERCENTAGE;
- } else if (unit.equals("em")) {
- values[1] = UNITS_EM;
- } else if (unit.equals("ex")) {
- values[1] = UNITS_EX;
- } else if (unit.equals("in")) {
- values[1] = UNITS_INCH;
- } else if (unit.equals("cm")) {
- values[1] = UNITS_CM;
- } else if (unit.equals("mm")) {
- values[1] = UNITS_MM;
- } else if (unit.equals("pt")) {
- values[1] = UNITS_POINTS;
- } else if (unit.equals("pc")) {
- values[1] = UNITS_PICAS;
- }
+ String symbol = matcher.group(3);
+ unit = Unit.getUnitFromSymbol(symbol);
}
} else {
throw new IllegalArgumentException("Invalid size argument: \"" + s
+ "\" (should match " + sizePattern.pattern() + ")");
}
- return values;
+ return new Size(size, unit);
+ }
+
+ private static class Size implements Serializable {
+ float size;
+ Unit unit;
+
+ public Size(float size, Unit unit) {
+ this.size = size;
+ this.unit = unit;
+ }
+
+ public float getSize() {
+ return size;
+ }
+
+ public Unit getUnit() {
+ return unit;
+ }
}
public interface ComponentErrorEvent extends Terminal.ErrorEvent {
@@ -1517,4 +1506,34 @@ public abstract class AbstractComponent implements Component, MethodEventSource
}
-} \ No newline at end of file
+ /*
+ * Actions
+ */
+
+ /**
+ * Gets the {@link ActionManager} used to manage the
+ * {@link ShortcutListener}s added to this {@link Field}.
+ *
+ * @return the ActionManager in use
+ */
+ protected ActionManager getActionManager() {
+ if (actionManager == null) {
+ actionManager = new ActionManager();
+ if (getRoot() != null) {
+ actionManager.setViewer(getRoot());
+ }
+ }
+ return actionManager;
+ }
+
+ public void addShortcutListener(ShortcutListener shortcut) {
+ getActionManager().addAction(shortcut);
+ }
+
+ public void removeShortcutListener(ShortcutListener shortcut) {
+ if (actionManager != null) {
+ actionManager.removeAction(shortcut);
+ }
+ }
+
+}
diff --git a/src/com/vaadin/ui/AbstractComponentContainer.java b/src/com/vaadin/ui/AbstractComponentContainer.java
index 5d5218307a..bbe2c20ea5 100644
--- a/src/com/vaadin/ui/AbstractComponentContainer.java
+++ b/src/com/vaadin/ui/AbstractComponentContainer.java
@@ -226,7 +226,7 @@ public abstract class AbstractComponentContainer extends AbstractComponent
}
@Override
- public void setWidth(float width, int unit) {
+ public void setWidth(float width, Unit unit) {
/*
* child tree repaints may be needed, due to our fall back support for
* invalid relative sizes
@@ -237,9 +237,9 @@ public abstract class AbstractComponentContainer extends AbstractComponent
// children currently in invalid state may need repaint
dirtyChildren = getInvalidSizedChildren(false);
} else if ((width == SIZE_UNDEFINED && getWidth() != SIZE_UNDEFINED)
- || (unit == UNITS_PERCENTAGE
- && getWidthUnits() != UNITS_PERCENTAGE && !ComponentSizeValidator
- .parentCanDefineWidth(this))) {
+ || (unit == Unit.PERCENTAGE
+ && getWidthUnits() != Unit.PERCENTAGE && !ComponentSizeValidator
+ .parentCanDefineWidth(this))) {
/*
* relative width children may get to invalid state if width becomes
* invalid. Width may also become invalid if units become percentage
@@ -326,7 +326,7 @@ public abstract class AbstractComponentContainer extends AbstractComponent
}
@Override
- public void setHeight(float height, int unit) {
+ public void setHeight(float height, Unit unit) {
/*
* child tree repaints may be needed, due to our fall back support for
* invalid relative sizes
@@ -337,9 +337,9 @@ public abstract class AbstractComponentContainer extends AbstractComponent
// children currently in invalid state may need repaint
dirtyChildren = getInvalidSizedChildren(true);
} else if ((height == SIZE_UNDEFINED && getHeight() != SIZE_UNDEFINED)
- || (unit == UNITS_PERCENTAGE
- && getHeightUnits() != UNITS_PERCENTAGE && !ComponentSizeValidator
- .parentCanDefineHeight(this))) {
+ || (unit == Unit.PERCENTAGE
+ && getHeightUnits() != Unit.PERCENTAGE && !ComponentSizeValidator
+ .parentCanDefineHeight(this))) {
/*
* relative height children may get to invalid state if height
* becomes invalid. Height may also become invalid if units become
diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java
index 9ea9bbba2e..4217f5f6fe 100644
--- a/src/com/vaadin/ui/AbstractField.java
+++ b/src/com/vaadin/ui/AbstractField.java
@@ -6,19 +6,24 @@ package com.vaadin.ui;
import java.io.Serializable;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
+import java.util.logging.Logger;
+import com.vaadin.Application;
import com.vaadin.data.Buffered;
import com.vaadin.data.Property;
import com.vaadin.data.Validatable;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
+import com.vaadin.data.util.converter.Converter;
+import com.vaadin.data.util.converter.ConverterFactory;
import com.vaadin.event.Action;
-import com.vaadin.event.ActionManager;
import com.vaadin.event.ShortcutAction;
import com.vaadin.event.ShortcutListener;
import com.vaadin.terminal.CompositeErrorMessage;
@@ -53,21 +58,29 @@ import com.vaadin.terminal.PaintTarget;
* @since 3.0
*/
@SuppressWarnings("serial")
-public abstract class AbstractField extends AbstractComponent implements Field,
- Property.ReadOnlyStatusChangeListener,
+public abstract class AbstractField<T> extends AbstractComponent implements
+ Field<T>, Property.ReadOnlyStatusChangeListener,
Property.ReadOnlyStatusChangeNotifier, Action.ShortcutNotifier {
/* Private members */
+ private static final Logger logger = Logger.getLogger(AbstractField.class
+ .getName());
+
/**
* Value of the abstract field.
*/
- private Object value;
+ private T value;
/**
+ * A converter used to convert from the data model type to the field type
+ * and vice versa.
+ */
+ private Converter<T, Object> converter = null;
+ /**
* Connected data-source.
*/
- private Property dataSource = null;
+ private Property<?> dataSource = null;
/**
* The list of validators.
@@ -127,15 +140,14 @@ public abstract class AbstractField extends AbstractComponent implements Field,
private String requiredError = "";
/**
- * Is automatic validation enabled.
+ * The error message that is shown when the field value cannot be converted.
*/
- private boolean validationVisible = true;
+ private String conversionError = "Could not convert value to {0}";
/**
- * Keeps track of the Actions added to this component; the actual
- * handling/notifying is delegated, usually to the containing window.
+ * Is automatic validation enabled.
*/
- private ActionManager actionManager;
+ private boolean validationVisible = true;
private boolean valueWasModifiedByDataSourceDuringCommit;
@@ -185,11 +197,16 @@ public abstract class AbstractField extends AbstractComponent implements Field,
&& getErrorMessage() != null;
}
- /*
- * Gets the field type Don't add a JavaDoc comment here, we use the default
- * documentation from the implemented interface.
+ /**
+ * Returns the type of the Field. The methods <code>getValue</code> and
+ * <code>setValue</code> must be compatible with this type: one must be able
+ * to safely cast the value returned from <code>getValue</code> to the given
+ * type and pass any variable assignable to this type as an argument to
+ * <code>setValue</code>.
+ *
+ * @return the type of the Field
*/
- public abstract Class<?> getType();
+ public abstract Class<? extends T> getType();
/**
* The abstract field is read only also if the data source is in read only
@@ -237,23 +254,21 @@ public abstract class AbstractField extends AbstractComponent implements Field,
public void commit() throws Buffered.SourceException, InvalidValueException {
if (dataSource != null && !dataSource.isReadOnly()) {
if ((isInvalidCommitted() || isValid())) {
- final Object newValue = getValue();
try {
// Commits the value to datasource.
valueWasModifiedByDataSourceDuringCommit = false;
committingValueToDataSource = true;
- dataSource.setValue(newValue);
-
+ getPropertyDataSource().setValue(getConvertedValue());
} catch (final Throwable e) {
// Sets the buffering state.
- currentBufferedSourceException = new Buffered.SourceException(
+ SourceException sourceException = new Buffered.SourceException(
this, e);
- requestRepaint();
+ setCurrentBufferedSourceException(sourceException);
// Throws the source exception.
- throw currentBufferedSourceException;
+ throw sourceException;
} finally {
committingValueToDataSource = false;
}
@@ -266,15 +281,14 @@ public abstract class AbstractField extends AbstractComponent implements Field,
boolean repaintNeeded = false;
// The abstract field is not modified anymore
- if (modified) {
- modified = false;
+ if (isModified()) {
+ setModified(false);
repaintNeeded = true;
}
// If successful, remove set the buffering state to be ok
- if (currentBufferedSourceException != null) {
- currentBufferedSourceException = null;
- repaintNeeded = true;
+ if (getCurrentBufferedSourceException() != null) {
+ setCurrentBufferedSourceException(null);
}
if (valueWasModifiedByDataSourceDuringCommit) {
@@ -294,19 +308,18 @@ public abstract class AbstractField extends AbstractComponent implements Field,
if (dataSource != null) {
// Gets the correct value from datasource
- Object newValue;
+ T newFieldValue;
try {
// Discards buffer by overwriting from datasource
- newValue = String.class == getType() ? dataSource.toString()
- : dataSource.getValue();
+ newFieldValue = convertFromDataSource(getDataSourceValue());
// If successful, remove set the buffering state to be ok
- if (currentBufferedSourceException != null) {
- currentBufferedSourceException = null;
- requestRepaint();
+ if (getCurrentBufferedSourceException() != null) {
+ setCurrentBufferedSourceException(null);
}
} catch (final Throwable e) {
+ // FIXME: What should really be done here if conversion fails?
// Sets the buffering state
currentBufferedSourceException = new Buffered.SourceException(
@@ -318,22 +331,46 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
final boolean wasModified = isModified();
- modified = false;
+ setModified(false);
// If the new value differs from the previous one
- if ((newValue == null && value != null)
- || (newValue != null && !newValue.equals(value))) {
- setInternalValue(newValue);
+ if (!equals(newFieldValue, getInternalValue())) {
+ setInternalValue(newFieldValue);
fireValueChange(false);
- }
-
- // If the value did not change, but the modification status did
- else if (wasModified) {
+ } else if (wasModified) {
+ // If the value did not change, but the modification status did
requestRepaint();
}
}
}
+ /**
+ * Gets the value from the data source. This is only here because of clarity
+ * in the code that handles both the data model value and the field value.
+ *
+ * @return The value of the property data source
+ */
+ private Object getDataSourceValue() {
+ return dataSource.getValue();
+ }
+
+ /**
+ * Returns the field value. This is always identical to {@link #getValue()}
+ * and only here because of clarity in the code that handles both the data
+ * model value and the field value.
+ *
+ * @return The value of the field
+ */
+ private T getFieldValue() {
+ // Give the value from abstract buffers if the field if possible
+ if (dataSource == null || !isReadThrough() || isModified()) {
+ return getInternalValue();
+ }
+
+ // There is no buffered value so use whatever the data model provides
+ return convertFromDataSource(getDataSourceValue());
+ }
+
/*
* Has the field been modified since the last commit()? Don't add a JavaDoc
* comment here, we use the default documentation from the implemented
@@ -343,6 +380,10 @@ public abstract class AbstractField extends AbstractComponent implements Field,
return modified;
}
+ private void setModified(boolean modified) {
+ this.modified = modified;
+ }
+
/*
* Tests if the field is in write-through mode. Don't add a JavaDoc comment
* here, we use the default documentation from the implemented interface.
@@ -351,11 +392,28 @@ public abstract class AbstractField extends AbstractComponent implements Field,
return writeThroughMode;
}
- /*
- * Sets the field's write-through mode to the specified status Don't add a
- * JavaDoc comment here, we use the default documentation from the
- * implemented interface.
+ /**
+ * Sets the field's write-through mode to the specified status. When
+ * switching the write-through mode on, a {@link #commit()} will be
+ * performed.
+ *
+ * @see #setBuffered(boolean) for an easier way to control read through and
+ * write through modes
+ *
+ * @param writeThrough
+ * Boolean value to indicate if the object should be in
+ * write-through mode after the call.
+ * @throws SourceException
+ * If the operation fails because of an exception is thrown by
+ * the data source.
+ * @throws InvalidValueException
+ * If the implicit commit operation fails because of a
+ * validation error.
+ * @deprecated Use {@link #setBuffered(boolean)} instead. Note that
+ * setReadThrough(true), setWriteThrough(true) equals
+ * setBuffered(false)
*/
+ @Deprecated
public void setWriteThrough(boolean writeThrough)
throws Buffered.SourceException, InvalidValueException {
if (writeThroughMode == writeThrough) {
@@ -375,38 +433,96 @@ public abstract class AbstractField extends AbstractComponent implements Field,
return readThroughMode;
}
- /*
- * Sets the field's read-through mode to the specified status Don't add a
- * JavaDoc comment here, we use the default documentation from the
- * implemented interface.
+ /**
+ * Sets the field's read-through mode to the specified status. When
+ * switching read-through mode on, the object's value is updated from the
+ * data source.
+ *
+ * @see #setBuffered(boolean) for an easier way to control read through and
+ * write through modes
+ *
+ * @param readThrough
+ * Boolean value to indicate if the object should be in
+ * read-through mode after the call.
+ *
+ * @throws SourceException
+ * If the operation fails because of an exception is thrown by
+ * the data source. The cause is included in the exception.
+ * @deprecated Use {@link #setBuffered(boolean)} instead. Note that
+ * setReadThrough(true), setWriteThrough(true) equals
+ * setBuffered(false)
*/
+ @Deprecated
public void setReadThrough(boolean readThrough)
throws Buffered.SourceException {
if (readThroughMode == readThrough) {
return;
}
readThroughMode = readThrough;
- if (!isModified() && readThroughMode && dataSource != null) {
- setInternalValue(String.class == getType() ? dataSource.toString()
- : dataSource.getValue());
+ if (!isModified() && readThroughMode && getPropertyDataSource() != null) {
+ setInternalValue(convertFromDataSource(getDataSourceValue()));
fireValueChange(false);
}
}
+ /**
+ * Sets the buffered mode of this Field.
+ * <p>
+ * When the field is in buffered mode, changes will not be committed to the
+ * property data source until {@link #commit()} is called.
+ * </p>
+ * <p>
+ * Changing buffered mode will change the read through and write through
+ * state for the field.
+ * </p>
+ * <p>
+ * Mixing calls to {@link #setBuffered(boolean)} and
+ * {@link #setReadThrough(boolean)} or {@link #setWriteThrough(boolean)} is
+ * generally a bad idea.
+ * </p>
+ *
+ * @param buffered
+ * true if buffered mode should be turned on, false otherwise
+ */
+ public void setBuffered(boolean buffered) {
+ setReadThrough(!buffered);
+ setWriteThrough(!buffered);
+ }
+
+ /**
+ * Checks the buffered mode of this Field.
+ * <p>
+ * This method only returns true if both read and write buffering is used.
+ *
+ * @return true if buffered mode is on, false otherwise
+ */
+ public boolean isBuffered() {
+ return !isReadThrough() && !isWriteThrough();
+ }
+
/* Property interface implementation */
/**
- * Returns the value of the Property in human readable textual format.
+ * Returns the (field) value converted to a String using toString().
*
* @see java.lang.Object#toString()
+ * @deprecated Instead use {@link #getValue()} to get the value of the
+ * field, {@link #getConvertedValue()} to get the field value
+ * converted to the data model type or
+ * {@link #getPropertyDataSource()} .getValue() to get the value
+ * of the data source.
*/
+ @Deprecated
@Override
public String toString() {
- final Object value = getValue();
+ logger.warning("You are using AbstractField.toString() to get the value for a "
+ + getClass().getSimpleName()
+ + ". This is not recommended and will not be supported in future versions.");
+ final Object value = getFieldValue();
if (value == null) {
return null;
}
- return getValue().toString();
+ return value.toString();
}
/**
@@ -414,67 +530,63 @@ public abstract class AbstractField extends AbstractComponent implements Field,
*
* <p>
* This is the visible, modified and possible invalid value the user have
- * entered to the field. In the read-through mode, the abstract buffer is
- * also updated and validation is performed.
+ * entered to the field.
* </p>
*
* <p>
* Note that the object returned is compatible with getType(). For example,
* if the type is String, this returns Strings even when the underlying
- * datasource is of some other type. In order to access the datasources
- * native type, use getPropertyDatasource().getValue() instead.
+ * datasource is of some other type. In order to access the converted value,
+ * use {@link #getConvertedValue()} and to access the value of the property
+ * data source, use {@link Property#getValue()} for the property data
+ * source.
* </p>
*
* <p>
- * Note that when you extend AbstractField, you must reimplement this method
- * if datasource.getValue() is not assignable to class returned by getType()
- * AND getType() is not String. In case of Strings, getValue() calls
- * datasource.toString() instead of datasource.getValue().
+ * Since Vaadin 7.0, no implicit conversions between other data types and
+ * String are performed, but a converter is used if set.
* </p>
*
* @return the current value of the field.
*/
- public Object getValue() {
-
- // Give the value from abstract buffers if the field if possible
- if (dataSource == null || !isReadThrough() || isModified()) {
- return value;
- }
-
- Object newValue = String.class == getType() ? dataSource.toString()
- : dataSource.getValue();
-
- return newValue;
+ public T getValue() {
+ return getFieldValue();
}
/**
* Sets the value of the field.
*
- * @param newValue
+ * @param newFieldValue
* the New value of the field.
* @throws Property.ReadOnlyException
- * @throws Property.ConversionException
*/
- public void setValue(Object newValue) throws Property.ReadOnlyException,
- Property.ConversionException {
- setValue(newValue, false);
+ public void setValue(Object newFieldValue)
+ throws Property.ReadOnlyException, Converter.ConversionException {
+ // This check is needed as long as setValue accepts Object instead of T
+ if (newFieldValue != null) {
+ if (!getType().isAssignableFrom(newFieldValue.getClass())) {
+ throw new Converter.ConversionException("Value of type "
+ + newFieldValue.getClass() + " cannot be assigned to "
+ + getClass().getName());
+ }
+ }
+ setValue((T) newFieldValue, false);
}
/**
* Sets the value of the field.
*
- * @param newValue
+ * @param newFieldValue
* the New value of the field.
* @param repaintIsNotNeeded
* True iff caller is sure that repaint is not needed.
* @throws Property.ReadOnlyException
- * @throws Property.ConversionException
*/
- protected void setValue(Object newValue, boolean repaintIsNotNeeded)
- throws Property.ReadOnlyException, Property.ConversionException {
+ protected void setValue(T newFieldValue, boolean repaintIsNotNeeded)
+ throws Property.ReadOnlyException, Converter.ConversionException,
+ InvalidValueException {
- if ((newValue == null && value != null)
- || (newValue != null && !newValue.equals(value))) {
+ if (!equals(newFieldValue, getInternalValue())) {
// Read only fields can not be changed
if (isReadOnly()) {
@@ -483,24 +595,24 @@ public abstract class AbstractField extends AbstractComponent implements Field,
// Repaint is needed even when the client thinks that it knows the
// new state if validity of the component may change
- if (repaintIsNotNeeded && (isRequired() || getValidators() != null)) {
+ if (repaintIsNotNeeded
+ && (isRequired() || getValidators() != null || getConverter() != null)) {
repaintIsNotNeeded = false;
}
- // If invalid values are not allowed, the value must be checked
if (!isInvalidAllowed()) {
- final Collection<Validator> v = getValidators();
- if (v != null) {
- for (final Iterator<Validator> i = v.iterator(); i
- .hasNext();) {
- (i.next()).validate(newValue);
- }
- }
+ /*
+ * If invalid values are not allowed the value must be validated
+ * before it is set. If validation fails, the
+ * InvalidValueException is thrown and the internal value is not
+ * updated.
+ */
+ validate(newFieldValue);
}
// Changes the value
- setInternalValue(newValue);
- modified = dataSource != null;
+ setInternalValue(newFieldValue);
+ setModified(dataSource != null);
valueWasModifiedByDataSourceDuringCommit = false;
// In write through mode , try to commit
@@ -510,10 +622,11 @@ public abstract class AbstractField extends AbstractComponent implements Field,
// Commits the value to datasource
committingValueToDataSource = true;
- dataSource.setValue(newValue);
+ getPropertyDataSource().setValue(
+ convertToDataSource(newFieldValue));
// The buffer is now unmodified
- modified = false;
+ setModified(false);
} catch (final Throwable e) {
@@ -530,9 +643,8 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
// If successful, remove set the buffering state to be ok
- if (currentBufferedSourceException != null) {
- currentBufferedSourceException = null;
- requestRepaint();
+ if (getCurrentBufferedSourceException() != null) {
+ setCurrentBufferedSourceException(null);
}
if (valueWasModifiedByDataSourceDuringCommit) {
@@ -549,6 +661,13 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
}
+ private static boolean equals(Object value1, Object value2) {
+ if (value1 == null) {
+ return value2 == null;
+ }
+ return value1.equals(value2);
+ }
+
/* External data source */
/**
@@ -591,7 +710,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
public void setPropertyDataSource(Property newDataSource) {
// Saves the old value
- final Object oldValue = value;
+ final Object oldValue = getInternalValue();
// Stops listening the old data source changes
if (dataSource != null
@@ -609,17 +728,32 @@ public abstract class AbstractField extends AbstractComponent implements Field,
// Sets the new data source
dataSource = newDataSource;
+ // Check if the current converter is compatible.
+ if (newDataSource != null
+ && (getConverter() == null || !newDataSource.getType()
+ .isAssignableFrom(getConverter().getModelType()))) {
+ // Changing from e.g. Number -> Double should set a new converter,
+ // changing from Double -> Number can keep the old one (Property
+ // accepts Number)
+
+ // Set a new converter if there is a new data source and
+ // there is no old converter or the old is incompatible.
+ setConverter(newDataSource.getType());
+ }
// Gets the value from source
try {
if (dataSource != null) {
- setInternalValue(String.class == getType() ? dataSource
- .toString() : dataSource.getValue());
+ T fieldValue = convertFromDataSource(getDataSourceValue());
+ setInternalValue(fieldValue);
+ }
+ setModified(false);
+ if (getCurrentBufferedSourceException() != null) {
+ setCurrentBufferedSourceException(null);
}
- modified = false;
} catch (final Throwable e) {
- currentBufferedSourceException = new Buffered.SourceException(this,
- e);
- modified = true;
+ setCurrentBufferedSourceException(new Buffered.SourceException(
+ this, e));
+ setModified(true);
}
// Listens the new data source if possible
@@ -644,12 +778,159 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
// Fires value change if the value has changed
+ T value = getInternalValue();
if ((value != oldValue)
&& ((value != null && !value.equals(oldValue)) || value == null)) {
fireValueChange(false);
}
}
+ /**
+ * Retrieves a converter for the field from the converter factory defined
+ * for the application. Clears the converter if no application reference is
+ * available or if the factory returns null.
+ *
+ * @param datamodelType
+ * The type of the data model that we want to be able to convert
+ * from
+ */
+ public void setConverter(Class<?> datamodelType) {
+ Converter<T, ?> converter = null;
+
+ Application app = Application.getCurrentApplication();
+ if (app != null) {
+ ConverterFactory factory = app.getConverterFactory();
+ converter = (Converter<T, ?>) factory.createConverter(getType(),
+ datamodelType);
+ }
+ setConverter(converter);
+ }
+
+ /**
+ * Convert the given value from the data source type to the UI type.
+ *
+ * @param newValue
+ * The data source value to convert.
+ * @return The converted value that is compatible with the UI type or the
+ * original value if its type is compatible and no converter is set.
+ * @throws Converter.ConversionException
+ * if there is no converter and the type is not compatible with
+ * the data source type.
+ */
+ @SuppressWarnings("unchecked")
+ private T convertFromDataSource(Object newValue)
+ throws Converter.ConversionException {
+ if (converter != null) {
+ return converter.convertToPresentation(newValue, getLocale());
+ }
+ if (newValue == null) {
+ return null;
+ }
+
+ if (getType().isAssignableFrom(newValue.getClass())) {
+ return (T) newValue;
+ } else {
+ throw new Converter.ConversionException(
+ "Unable to convert value of type "
+ + newValue.getClass().getName()
+ + " to "
+ + getType()
+ + ". No converter is set and the types are not compatible.");
+ }
+ }
+
+ /**
+ * Convert the given value from the UI type to the data source type.
+ *
+ * @param fieldValue
+ * The value to convert. Typically returned by
+ * {@link #getFieldValue()}
+ * @return The converted value that is compatible with the data source type.
+ * @throws Converter.ConversionException
+ * if there is no converter and the type is not compatible with
+ * the data source type.
+ */
+ private Object convertToDataSource(T fieldValue)
+ throws Converter.ConversionException {
+ if (converter != null) {
+ /*
+ * If there is a converter, always use it. It must convert or throw
+ * an exception.
+ */
+ try {
+ return converter.convertToModel(fieldValue, getLocale());
+ } catch (com.vaadin.data.util.converter.Converter.ConversionException e) {
+ throw new Converter.ConversionException(
+ getConversionError(converter.getModelType()), e);
+ }
+ }
+
+ if (fieldValue == null) {
+ // Null should always be passed through the converter but if there
+ // is no converter we can safely return null
+ return null;
+ }
+
+ // check that the value class is compatible with the data source type
+ // (if data source set) or field type
+ Class<?> type;
+ if (getPropertyDataSource() != null) {
+ type = getPropertyDataSource().getType();
+ } else {
+ type = getType();
+ }
+
+ if (type.isAssignableFrom(fieldValue.getClass())) {
+ return fieldValue;
+ } else {
+ throw new Converter.ConversionException(getConversionError(type));
+ }
+ }
+
+ /**
+ * Returns the conversion error with {0} replaced by the data source type.
+ *
+ * @param dataSourceType
+ * The type of the data source
+ * @return The value conversion error string with parameters replaced.
+ */
+ protected String getConversionError(Class<?> dataSourceType) {
+ if (dataSourceType == null) {
+ return getConversionError();
+ } else {
+ return getConversionError().replace("{0}",
+ dataSourceType.getSimpleName());
+ }
+ }
+
+ /**
+ * Returns the current value (as returned by {@link #getValue()}) converted
+ * to the data source type.
+ * <p>
+ * This returns the same as {@link AbstractField#getValue()} if no converter
+ * has been set. The value is not necessarily the same as the data source
+ * value e.g. if the field is in buffered mode and has been modified.
+ * </p>
+ *
+ * @return The converted value that is compatible with the data source type
+ */
+ public Object getConvertedValue() {
+ return convertToDataSource(getFieldValue());
+ }
+
+ /**
+ * Sets the value of the field using a value of the data source type. The
+ * value given is converted to the field type and then assigned to the
+ * field. This will update the property data source in the same way as when
+ * {@link #setValue(Object)} is called.
+ *
+ * @param value
+ * The value to set. Must be the same type as the data source.
+ */
+ public void setConvertedValue(Object value) {
+ setValue(convertFromDataSource(value));
+ }
+
/* Validation */
/**
@@ -698,102 +979,99 @@ public abstract class AbstractField extends AbstractComponent implements Field,
* empty. If the field is empty it is considered valid if it is not required
* and invalid otherwise. Validators are never checked for empty fields.
*
+ * In most cases, {@link #validate()} should be used instead of
+ * {@link #isValid()} to also get the error message.
+ *
* @return <code>true</code> if all registered validators claim that the
* current value is valid or if the field is empty and not required,
* <code>false</code> otherwise.
*/
public boolean isValid() {
- if (isEmpty()) {
- if (isRequired()) {
- return false;
- } else {
- return true;
- }
- }
-
- if (validators == null) {
+ try {
+ validate();
return true;
+ } catch (InvalidValueException e) {
+ return false;
}
-
- final Object value = getValue();
- for (final Iterator<Validator> i = validators.iterator(); i.hasNext();) {
- if (!(i.next()).isValid(value)) {
- return false;
- }
- }
-
- return true;
}
/**
- * Checks the validity of the Validatable by validating the field with all
- * attached validators except when the field is empty. An empty field is
- * invalid if it is required and valid otherwise.
+ * Checks the validity of the Field.
+ *
+ * A field is invalid if it is set as required (using
+ * {@link #setRequired(boolean)} and is empty, if one or several of the
+ * validators added to the field indicate it is invalid or if the value
+ * cannot be converted provided a converter has been set.
*
* The "required" validation is a built-in validation feature. If the field
- * is required, but empty, validation will throw an EmptyValueException with
- * the error message set with setRequiredError().
+ * is required and empty this method throws an EmptyValueException with the
+ * error message set using {@link #setRequiredError(String)}.
*
* @see com.vaadin.data.Validatable#validate()
*/
public void validate() throws Validator.InvalidValueException {
- if (isEmpty()) {
- if (isRequired()) {
- throw new Validator.EmptyValueException(requiredError);
- } else {
- return;
- }
+ if (isRequired() && isEmpty()) {
+ throw new Validator.EmptyValueException(requiredError);
}
+ validate(getFieldValue());
+ }
- // If there is no validator, there can not be any errors
- if (validators == null) {
- return;
- }
+ /**
+ * Validates that the given value pass the validators for the field.
+ * <p>
+ * This method does not check the requiredness of the field.
+ *
+ * @param fieldValue
+ * The value to check
+ * @throws Validator.InvalidValueException
+ * if one or several validators fail
+ */
+ protected void validate(T fieldValue)
+ throws Validator.InvalidValueException {
- // Initialize temps
- Validator.InvalidValueException firstError = null;
- LinkedList<InvalidValueException> errors = null;
- final Object value = getValue();
+ Object valueToValidate = fieldValue;
- // Gets all the validation errors
- for (final Iterator<Validator> i = validators.iterator(); i.hasNext();) {
+ // If there is a converter we start by converting the value as we want
+ // to validate the converted value
+ if (getConverter() != null) {
try {
- (i.next()).validate(value);
- } catch (final Validator.InvalidValueException e) {
- if (firstError == null) {
- firstError = e;
- } else {
- if (errors == null) {
- errors = new LinkedList<InvalidValueException>();
- errors.add(firstError);
- }
- errors.add(e);
+ valueToValidate = getConverter().convertToModel(fieldValue,
+ getLocale());
+ } catch (Exception e) {
+ throw new InvalidValueException(
+ getConversionError(getConverter().getModelType()));
+ }
+ }
+
+ List<InvalidValueException> validationExceptions = new ArrayList<InvalidValueException>();
+ if (validators != null) {
+ // Gets all the validation errors
+ for (Validator v : validators) {
+ try {
+ v.validate(valueToValidate);
+ } catch (final Validator.InvalidValueException e) {
+ validationExceptions.add(e);
}
}
}
- // If there were no error
- if (firstError == null) {
+ // If there were no errors
+ if (validationExceptions.isEmpty()) {
return;
}
// If only one error occurred, throw it forwards
- if (errors == null) {
- throw firstError;
+ if (validationExceptions.size() == 1) {
+ throw validationExceptions.get(0);
}
- // Creates composite validator
- final Validator.InvalidValueException[] exceptions = new Validator.InvalidValueException[errors
- .size()];
- int index = 0;
- for (final Iterator<InvalidValueException> i = errors.iterator(); i
- .hasNext();) {
- exceptions[index++] = i.next();
- }
+ InvalidValueException[] exceptionArray = validationExceptions
+ .toArray(new InvalidValueException[validationExceptions.size()]);
- throw new Validator.InvalidValueException(null, exceptions);
+ // Create a composite validator and include all exceptions
+ throw new Validator.InvalidValueException(null, exceptionArray);
}
/**
@@ -857,13 +1135,13 @@ public abstract class AbstractField extends AbstractComponent implements Field,
// Return if there are no errors at all
if (superError == null && validationError == null
- && currentBufferedSourceException == null) {
+ && getCurrentBufferedSourceException() == null) {
return null;
}
// Throw combination of the error types
return new CompositeErrorMessage(new ErrorMessage[] { superError,
- validationError, currentBufferedSourceException });
+ validationError, getCurrentBufferedSourceException() });
}
@@ -949,8 +1227,8 @@ public abstract class AbstractField extends AbstractComponent implements Field,
* @VERSION@
* @since 3.0
*/
- public class ReadOnlyStatusChangeEvent extends Component.Event implements
- Property.ReadOnlyStatusChangeEvent, Serializable {
+ public static class ReadOnlyStatusChangeEvent extends Component.Event
+ implements Property.ReadOnlyStatusChangeEvent, Serializable {
/**
* New instance of text change event.
@@ -1014,10 +1292,8 @@ public abstract class AbstractField extends AbstractComponent implements Field,
public void valueChange(Property.ValueChangeEvent event) {
if (isReadThrough()) {
if (committingValueToDataSource) {
- boolean propertyNotifiesOfTheBufferedValue = event
- .getProperty().getValue() == value
- || (value != null && value.equals(event.getProperty()
- .getValue()));
+ boolean propertyNotifiesOfTheBufferedValue = equals(event
+ .getProperty().getValue(), getInternalValue());
if (!propertyNotifiesOfTheBufferedValue) {
/*
* Property (or chained property like PropertyFormatter) now
@@ -1040,7 +1316,7 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
private void readValueFromProperty(Property.ValueChangeEvent event) {
- setInternalValue(event.getProperty().getValue());
+ setInternalValue(convertFromDataSource(event.getProperty().getValue()));
}
@Override
@@ -1056,25 +1332,6 @@ public abstract class AbstractField extends AbstractComponent implements Field,
super.focus();
}
- /**
- * Creates abstract field by the type of the property.
- *
- * <p>
- * This returns most suitable field type for editing property of given type.
- * </p>
- *
- * @param propertyType
- * the Type of the property, that needs to be edited.
- * @deprecated use e.g.
- * {@link DefaultFieldFactory#createFieldByPropertyType(Class)}
- * instead
- */
- @Deprecated
- public static AbstractField constructField(Class<?> propertyType) {
- return (AbstractField) DefaultFieldFactory
- .createFieldByPropertyType(propertyType);
- }
-
/*
* (non-Javadoc)
*
@@ -1095,15 +1352,34 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
/**
+ * Returns the internal field value, which might not match the data source
+ * value e.g. if the field has been modified and is not in write-through
+ * mode.
+ *
+ * This method can be overridden by subclasses together with
+ * {@link #setInternalValue(Object)} to compute internal field value at
+ * runtime. When doing so, typically also {@link #isModified()} needs to be
+ * overridden and care should be taken in the management of the empty state
+ * and buffering support.
+ *
+ * @return internal field value
+ */
+ protected T getInternalValue() {
+ return value;
+ }
+
+ /**
* Sets the internal field value. This is purely used by AbstractField to
* change the internal Field value. It does not trigger valuechange events.
* It can be overridden by the inheriting classes to update all dependent
* variables.
*
+ * Subclasses can also override {@link #getInternalValue()} if necessary.
+ *
* @param newValue
* the new value to be set.
*/
- protected void setInternalValue(Object newValue) {
+ protected void setInternalValue(T newValue) {
value = newValue;
if (validators != null && !validators.isEmpty()) {
requestRepaint();
@@ -1111,27 +1387,6 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
/**
- * Notifies the component that it is connected to an application.
- *
- * @see com.vaadin.ui.Component#attach()
- */
- @Override
- public void attach() {
- super.attach();
- if (actionManager != null) {
- actionManager.setViewer(getWindow());
- }
- }
-
- @Override
- public void detach() {
- super.detach();
- if (actionManager != null) {
- actionManager.setViewer((Window) null);
- }
- }
-
- /**
* Is this field required. Required fields must filled by the user.
*
* If the field is required, it is visually indicated in the user interface.
@@ -1190,13 +1445,36 @@ public abstract class AbstractField extends AbstractComponent implements Field,
}
/**
+ * Gets the error that is shown if the field value cannot be converted to
+ * the data source type.
+ *
+ * @return The error that is shown if conversion of the field value fails
+ */
+ public String getConversionError() {
+ return conversionError;
+ }
+
+ /**
+ * Sets the error that is shown if the field value cannot be converted to
+ * the data source type. If {0} is present in the message, it will be
+ * replaced by the simple name of the data source type.
+ *
+ * @param valueConversionError
+ * Message to be shown when conversion of the value fails
+ */
+ public void setConversionError(String valueConversionError) {
+ this.conversionError = valueConversionError;
+ requestRepaint();
+ }
+
+ /**
* Is the field empty?
*
* In general, "empty" state is same as null. As an exception, TextField
* also treats empty string as "empty".
*/
protected boolean isEmpty() {
- return (getValue() == null);
+ return (getFieldValue() == null);
}
/**
@@ -1244,34 +1522,13 @@ public abstract class AbstractField extends AbstractComponent implements Field,
requestRepaint();
}
- /*
- * Actions
- */
-
/**
- * Gets the {@link ActionManager} used to manage the
- * {@link ShortcutListener}s added to this {@link Field}.
+ * Gets the current buffered source exception.
*
- * @return the ActionManager in use
+ * @return The current source exception
*/
- protected ActionManager getActionManager() {
- if (actionManager == null) {
- actionManager = new ActionManager();
- if (getWindow() != null) {
- actionManager.setViewer(getWindow());
- }
- }
- return actionManager;
- }
-
- public void addShortcutListener(ShortcutListener shortcut) {
- getActionManager().addAction(shortcut);
- }
-
- public void removeShortcutListener(ShortcutListener shortcut) {
- if (actionManager != null) {
- actionManager.removeAction(shortcut);
- }
+ protected Buffered.SourceException getCurrentBufferedSourceException() {
+ return currentBufferedSourceException;
}
/**
@@ -1329,4 +1586,28 @@ public abstract class AbstractField extends AbstractComponent implements Field,
focusable.focus();
}
}
-} \ No newline at end of file
+
+ /**
+ * Gets the converter used to convert the property data source value to the
+ * field value.
+ *
+ * @return The converter or null if none is set.
+ */
+ public Converter<T, Object> getConverter() {
+ return converter;
+ }
+
+ /**
+ * Sets the converter used to convert the field value to property data
+ * source type. The converter must have a presentation type that matches the
+ * field type.
+ *
+ * @param converter
+ * The new converter to use.
+ */
+ public void setConverter(Converter<T, ?> converter) {
+ this.converter = (Converter<T, Object>) converter;
+ requestRepaint();
+ }
+
+}
diff --git a/src/com/vaadin/ui/AbstractMedia.java b/src/com/vaadin/ui/AbstractMedia.java
index 9117bce997..369ef773b9 100644
--- a/src/com/vaadin/ui/AbstractMedia.java
+++ b/src/com/vaadin/ui/AbstractMedia.java
@@ -12,7 +12,7 @@ import java.util.List;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
-import com.vaadin.terminal.gwt.client.ui.VMediaBase;
+import com.vaadin.terminal.gwt.client.ui.VMediaBasePaintable;
/**
* Abstract base class for the HTML5 media components.
@@ -203,25 +203,27 @@ public class AbstractMedia extends AbstractComponent {
@Override
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
- target.addAttribute(VMediaBase.ATTR_CONTROLS, isShowControls());
+ target.addAttribute(VMediaBasePaintable.ATTR_CONTROLS, isShowControls());
if (getAltText() != null) {
- target.addAttribute(VMediaBase.ATTR_ALT_TEXT, getAltText());
+ target.addAttribute(VMediaBasePaintable.ATTR_ALT_TEXT, getAltText());
}
- target.addAttribute(VMediaBase.ATTR_HTML, isHtmlContentAllowed());
- target.addAttribute(VMediaBase.ATTR_AUTOPLAY, isAutoplay());
+ target.addAttribute(VMediaBasePaintable.ATTR_HTML,
+ isHtmlContentAllowed());
+ target.addAttribute(VMediaBasePaintable.ATTR_AUTOPLAY, isAutoplay());
for (Resource r : getSources()) {
- target.startTag(VMediaBase.TAG_SOURCE);
- target.addAttribute(VMediaBase.ATTR_RESOURCE, r);
- target.addAttribute(VMediaBase.ATTR_RESOURCE_TYPE, r.getMIMEType());
- target.endTag(VMediaBase.TAG_SOURCE);
+ target.startTag(VMediaBasePaintable.TAG_SOURCE);
+ target.addAttribute(VMediaBasePaintable.ATTR_RESOURCE, r);
+ target.addAttribute(VMediaBasePaintable.ATTR_RESOURCE_TYPE,
+ r.getMIMEType());
+ target.endTag(VMediaBasePaintable.TAG_SOURCE);
}
- target.addAttribute(VMediaBase.ATTR_MUTED, isMuted());
+ target.addAttribute(VMediaBasePaintable.ATTR_MUTED, isMuted());
if (play) {
- target.addAttribute(VMediaBase.ATTR_PLAY, true);
+ target.addAttribute(VMediaBasePaintable.ATTR_PLAY, true);
play = false;
}
if (pause) {
- target.addAttribute(VMediaBase.ATTR_PAUSE, true);
+ target.addAttribute(VMediaBasePaintable.ATTR_PAUSE, true);
pause = false;
}
}
diff --git a/src/com/vaadin/ui/AbstractSelect.java b/src/com/vaadin/ui/AbstractSelect.java
index bb49626741..5e086f0b8d 100644
--- a/src/com/vaadin/ui/AbstractSelect.java
+++ b/src/com/vaadin/ui/AbstractSelect.java
@@ -55,46 +55,91 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
* @since 5.0
*/
@SuppressWarnings("serial")
-public abstract class AbstractSelect extends AbstractField implements
+// TODO currently cannot specify type more precisely in case of multi-select
+public abstract class AbstractSelect extends AbstractField<Object> implements
Container, Container.Viewer, Container.PropertySetChangeListener,
Container.PropertySetChangeNotifier, Container.ItemSetChangeNotifier,
Container.ItemSetChangeListener {
+ public enum ItemCaptionMode {
+ /**
+ * Item caption mode: Item's ID's <code>String</code> representation is
+ * used as caption.
+ */
+ ID,
+ /**
+ * Item caption mode: Item's <code>String</code> representation is used
+ * as caption.
+ */
+ ITEM,
+ /**
+ * Item caption mode: Index of the item is used as caption. The index
+ * mode can only be used with the containers implementing the
+ * {@link com.vaadin.data.Container.Indexed} interface.
+ */
+ INDEX,
+ /**
+ * Item caption mode: If an Item has a caption it's used, if not, Item's
+ * ID's <code>String</code> representation is used as caption. <b>This
+ * is the default</b>.
+ */
+ EXPLICIT_DEFAULTS_ID,
+ /**
+ * Item caption mode: Captions must be explicitly specified.
+ */
+ EXPLICIT,
+ /**
+ * Item caption mode: Only icons are shown, captions are hidden.
+ */
+ ICON_ONLY,
+ /**
+ * Item caption mode: Item captions are read from property specified
+ * with <code>setItemCaptionPropertyId</code>.
+ */
+ PROPERTY;
+ }
+
/**
- * Item caption mode: Item's ID's <code>String</code> representation is used
- * as caption.
+ * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead
*/
- public static final int ITEM_CAPTION_MODE_ID = 0;
+ @Deprecated
+ public static final ItemCaptionMode ITEM_CAPTION_MODE_ID = ItemCaptionMode.ID;
+
/**
- * Item caption mode: Item's <code>String</code> representation is used as
- * caption.
+ * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead
*/
- public static final int ITEM_CAPTION_MODE_ITEM = 1;
+ @Deprecated
+ public static final ItemCaptionMode ITEM_CAPTION_MODE_ITEM = ItemCaptionMode.ITEM;
+
/**
- * Item caption mode: Index of the item is used as caption. The index mode
- * can only be used with the containers implementing the
- * {@link com.vaadin.data.Container.Indexed} interface.
+ * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead
*/
- public static final int ITEM_CAPTION_MODE_INDEX = 2;
+ @Deprecated
+ public static final ItemCaptionMode ITEM_CAPTION_MODE_INDEX = ItemCaptionMode.INDEX;
+
/**
- * Item caption mode: If an Item has a caption it's used, if not, Item's
- * ID's <code>String</code> representation is used as caption. <b>This is
- * the default</b>.
+ * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead
*/
- public static final int ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = 3;
+ @Deprecated
+ public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = ItemCaptionMode.EXPLICIT_DEFAULTS_ID;
+
/**
- * Item caption mode: Captions must be explicitly specified.
+ * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead
*/
- public static final int ITEM_CAPTION_MODE_EXPLICIT = 4;
+ @Deprecated
+ public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT = ItemCaptionMode.EXPLICIT;
+
/**
- * Item caption mode: Only icons are shown, captions are hidden.
+ * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead
*/
- public static final int ITEM_CAPTION_MODE_ICON_ONLY = 5;
+ @Deprecated
+ public static final ItemCaptionMode ITEM_CAPTION_MODE_ICON_ONLY = ItemCaptionMode.ICON_ONLY;
+
/**
- * Item caption mode: Item captions are read from property specified with
- * <code>setItemCaptionPropertyId</code>.
+ * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead
*/
- public static final int ITEM_CAPTION_MODE_PROPERTY = 6;
+ @Deprecated
+ public static final ItemCaptionMode ITEM_CAPTION_MODE_PROPERTY = ItemCaptionMode.PROPERTY;
/**
* Interface for option filtering, used to filter options based on user
@@ -174,7 +219,7 @@ public abstract class AbstractSelect extends AbstractField implements
/**
* Item caption mode.
*/
- private int itemCaptionMode = ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID;
+ private ItemCaptionMode itemCaptionMode = ItemCaptionMode.EXPLICIT_DEFAULTS_ID;
/**
* Item caption source property id.
@@ -515,16 +560,9 @@ public abstract class AbstractSelect extends AbstractField implements
// Sets the caption property, if used
if (getItemCaptionPropertyId() != null) {
- try {
- getContainerProperty(newItemCaption,
- getItemCaptionPropertyId()).setValue(
- newItemCaption);
- } catch (final Property.ConversionException ignored) {
- /*
- * The conversion exception is safely ignored, the
- * caption is just missing
- */
- }
+ getContainerProperty(newItemCaption,
+ getItemCaptionPropertyId())
+ .setValue(newItemCaption);
}
if (isMultiSelect()) {
Set values = new HashSet((Collection) getValue());
@@ -614,8 +652,7 @@ public abstract class AbstractSelect extends AbstractField implements
* @see com.vaadin.ui.AbstractField#setValue(java.lang.Object)
*/
@Override
- public void setValue(Object newValue) throws Property.ReadOnlyException,
- Property.ConversionException {
+ public void setValue(Object newValue) throws Property.ReadOnlyException {
if (newValue == getNullSelectionItemId()) {
newValue = null;
}
@@ -641,7 +678,7 @@ public abstract class AbstractSelect extends AbstractField implements
*/
@Override
protected void setValue(Object newValue, boolean repaintIsNotNeeded)
- throws Property.ReadOnlyException, Property.ConversionException {
+ throws Property.ReadOnlyException {
if (isMultiSelect()) {
if (newValue == null) {
@@ -729,7 +766,7 @@ public abstract class AbstractSelect extends AbstractField implements
*
* @see com.vaadin.data.Container#getContainerProperty(Object, Object)
*/
- public Property getContainerProperty(Object itemId, Object propertyId) {
+ public Property<?> getContainerProperty(Object itemId, Object propertyId) {
return items.getContainerProperty(itemId, propertyId);
}
@@ -1045,11 +1082,11 @@ public abstract class AbstractSelect extends AbstractField implements
switch (getItemCaptionMode()) {
- case ITEM_CAPTION_MODE_ID:
+ case ID:
caption = itemId.toString();
break;
- case ITEM_CAPTION_MODE_INDEX:
+ case INDEX:
if (items instanceof Container.Indexed) {
caption = String.valueOf(((Container.Indexed) items)
.indexOfId(itemId));
@@ -1058,29 +1095,32 @@ public abstract class AbstractSelect extends AbstractField implements
}
break;
- case ITEM_CAPTION_MODE_ITEM:
+ case ITEM:
final Item i = getItem(itemId);
if (i != null) {
caption = i.toString();
}
break;
- case ITEM_CAPTION_MODE_EXPLICIT:
+ case EXPLICIT:
caption = itemCaptions.get(itemId);
break;
- case ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID:
+ case EXPLICIT_DEFAULTS_ID:
caption = itemCaptions.get(itemId);
if (caption == null) {
caption = itemId.toString();
}
break;
- case ITEM_CAPTION_MODE_PROPERTY:
- final Property p = getContainerProperty(itemId,
+ case PROPERTY:
+ final Property<?> p = getContainerProperty(itemId,
getItemCaptionPropertyId());
if (p != null) {
- caption = p.toString();
+ Object value = p.getValue();
+ if (value != null) {
+ caption = value.toString();
+ }
}
break;
}
@@ -1090,7 +1130,7 @@ public abstract class AbstractSelect extends AbstractField implements
}
/**
- * Sets the icon for an item.
+ * Sets tqhe icon for an item.
*
* @param itemId
* the id of the item to be assigned an icon.
@@ -1125,7 +1165,7 @@ public abstract class AbstractSelect extends AbstractField implements
return null;
}
- final Property ip = getContainerProperty(itemId,
+ final Property<?> ip = getContainerProperty(itemId,
getItemIconPropertyId());
if (ip == null) {
return null;
@@ -1167,8 +1207,8 @@ public abstract class AbstractSelect extends AbstractField implements
* @param mode
* the One of the modes listed above.
*/
- public void setItemCaptionMode(int mode) {
- if (ITEM_CAPTION_MODE_ID <= mode && mode <= ITEM_CAPTION_MODE_PROPERTY) {
+ public void setItemCaptionMode(ItemCaptionMode mode) {
+ if (mode != null) {
itemCaptionMode = mode;
requestRepaint();
}
@@ -1202,7 +1242,7 @@ public abstract class AbstractSelect extends AbstractField implements
*
* @return the One of the modes listed above.
*/
- public int getItemCaptionMode() {
+ public ItemCaptionMode getItemCaptionMode() {
return itemCaptionMode;
}
@@ -1216,7 +1256,9 @@ public abstract class AbstractSelect extends AbstractField implements
* null resets the item caption mode to
* <code>ITEM_CAPTION_EXPLICIT_DEFAULTS_ID</code>.
* </p>
- *
+ * <p>
+ * Note that the type of the property used for caption must be String
+ * </p>
* <p>
* Setting the property id to null disables this feature. The id is null by
* default
@@ -1691,7 +1733,7 @@ public abstract class AbstractSelect extends AbstractField implements
public void addNotifierForItem(Object itemId) {
switch (getItemCaptionMode()) {
- case ITEM_CAPTION_MODE_ITEM:
+ case ITEM:
final Item i = getItem(itemId);
if (i == null) {
return;
@@ -1704,7 +1746,7 @@ public abstract class AbstractSelect extends AbstractField implements
Collection<?> pids = i.getItemPropertyIds();
if (pids != null) {
for (Iterator<?> it = pids.iterator(); it.hasNext();) {
- Property p = i.getItemProperty(it.next());
+ Property<?> p = i.getItemProperty(it.next());
if (p != null
&& p instanceof Property.ValueChangeNotifier) {
((Property.ValueChangeNotifier) p)
@@ -1715,8 +1757,8 @@ public abstract class AbstractSelect extends AbstractField implements
}
break;
- case ITEM_CAPTION_MODE_PROPERTY:
- final Property p = getContainerProperty(itemId,
+ case PROPERTY:
+ final Property<?> p = getContainerProperty(itemId,
getItemCaptionPropertyId());
if (p != null && p instanceof Property.ValueChangeNotifier) {
((Property.ValueChangeNotifier) p)
diff --git a/src/com/vaadin/ui/AbstractSplitPanel.java b/src/com/vaadin/ui/AbstractSplitPanel.java
index adb84f9d9d..e03e73a781 100644
--- a/src/com/vaadin/ui/AbstractSplitPanel.java
+++ b/src/com/vaadin/ui/AbstractSplitPanel.java
@@ -15,7 +15,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanel;
+import com.vaadin.terminal.gwt.client.ui.VAbstractSplitPanelPaintable;
import com.vaadin.tools.ReflectTools;
/**
@@ -37,13 +37,13 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
private int pos = 50;
- private int posUnit = UNITS_PERCENTAGE;
+ private Unit posUnit = Unit.PERCENTAGE;
private boolean posReversed = false;
private boolean locked = false;
- private static final String SPLITTER_CLICK_EVENT = VSplitPanel.SPLITTER_CLICK_EVENT_IDENTIFIER;
+ private static final String SPLITTER_CLICK_EVENT = VAbstractSplitPanelPaintable.SPLITTER_CLICK_EVENT_IDENTIFIER;
/**
* Modifiable and Serializable Iterator for the components, used by
@@ -209,7 +209,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
- final String position = pos + UNIT_SYMBOLS[posUnit];
+ final String position = pos + posUnit.getSymbol();
target.addAttribute("position", position);
@@ -278,7 +278,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
* @param unit
* the unit (from {@link Sizeable}) in which the size is given.
*/
- public void setSplitPosition(int pos, int unit) {
+ public void setSplitPosition(int pos, Unit unit) {
setSplitPosition(pos, unit, true, false);
}
@@ -294,7 +294,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
* second region else it is measured by the first region
*
*/
- public void setSplitPosition(int pos, int unit, boolean reverse) {
+ public void setSplitPosition(int pos, Unit unit, boolean reverse) {
setSplitPosition(pos, unit, true, reverse);
}
@@ -313,7 +313,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
*
* @return unit of position of the splitter
*/
- public int getSplitPositionUnit() {
+ public Unit getSplitPositionUnit() {
return posUnit;
}
@@ -329,9 +329,9 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
* position info has come from the client side, thus it already
* knows the position.
*/
- private void setSplitPosition(int pos, int unit, boolean repaintNeeded,
+ private void setSplitPosition(int pos, Unit unit, boolean repaintNeeded,
boolean reverse) {
- if (unit != UNITS_PERCENTAGE && unit != UNITS_PIXELS) {
+ if (unit != Unit.PERCENTAGE && unit != Unit.PIXELS) {
throw new IllegalArgumentException(
"Only percentage and pixel units are allowed");
}
diff --git a/src/com/vaadin/ui/AbstractTextField.java b/src/com/vaadin/ui/AbstractTextField.java
index 346d370bd5..96d8a11410 100644
--- a/src/com/vaadin/ui/AbstractTextField.java
+++ b/src/com/vaadin/ui/AbstractTextField.java
@@ -20,7 +20,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VTextField;
-public abstract class AbstractTextField extends AbstractField implements
+public abstract class AbstractTextField extends AbstractField<String> implements
BlurNotifier, FocusNotifier, TextChangeNotifier {
/**
@@ -173,8 +173,8 @@ public abstract class AbstractTextField extends AbstractField implements
}
@Override
- public Object getValue() {
- Object v = super.getValue();
+ public String getValue() {
+ String v = super.getValue();
if (format == null || v == null) {
return v;
}
@@ -252,7 +252,7 @@ public abstract class AbstractTextField extends AbstractField implements
}
@Override
- public Class getType() {
+ public Class<String> getType() {
return String.class;
}
@@ -375,7 +375,7 @@ public abstract class AbstractTextField extends AbstractField implements
@Override
protected boolean isEmpty() {
- return super.isEmpty() || toString().length() == 0;
+ return super.isEmpty() || getValue().length() == 0;
}
/**
@@ -463,7 +463,7 @@ public abstract class AbstractTextField extends AbstractField implements
}
@Override
- protected void setInternalValue(Object newValue) {
+ protected void setInternalValue(String newValue) {
if (changingVariables && !textChangeEventPending) {
/*
@@ -505,8 +505,7 @@ public abstract class AbstractTextField extends AbstractField implements
}
@Override
- public void setValue(Object newValue) throws ReadOnlyException,
- ConversionException {
+ public void setValue(Object newValue) throws ReadOnlyException {
super.setValue(newValue);
/*
* Make sure w reset lastKnownTextContent field on value change. The
@@ -515,7 +514,7 @@ public abstract class AbstractTextField extends AbstractField implements
* case. AbstractField optimizes value change if the existing value is
* reset. Also we need to force repaint if the flag is on.
*/
- if(lastKnownTextContent != null) {
+ if (lastKnownTextContent != null) {
lastKnownTextContent = null;
requestRepaint();
}
@@ -753,4 +752,4 @@ public abstract class AbstractTextField extends AbstractField implements
removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
}
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/ui/Accordion.java b/src/com/vaadin/ui/Accordion.java
index 5cf805615c..4ee75326ff 100644
--- a/src/com/vaadin/ui/Accordion.java
+++ b/src/com/vaadin/ui/Accordion.java
@@ -3,7 +3,7 @@
*/
package com.vaadin.ui;
-import com.vaadin.terminal.gwt.client.ui.VAccordion;
+import com.vaadin.terminal.gwt.client.ui.VAccordionPaintable;
/**
* An accordion is a component similar to a {@link TabSheet}, but with a
@@ -16,8 +16,7 @@ import com.vaadin.terminal.gwt.client.ui.VAccordion;
*
* @see TabSheet
*/
-@SuppressWarnings("serial")
-@ClientWidget(VAccordion.class)
+@ClientWidget(VAccordionPaintable.class)
public class Accordion extends TabSheet {
}
diff --git a/src/com/vaadin/ui/Audio.java b/src/com/vaadin/ui/Audio.java
index 574c1f4186..048ef81c10 100644
--- a/src/com/vaadin/ui/Audio.java
+++ b/src/com/vaadin/ui/Audio.java
@@ -5,7 +5,7 @@
package com.vaadin.ui;
import com.vaadin.terminal.Resource;
-import com.vaadin.terminal.gwt.client.ui.VAudio;
+import com.vaadin.terminal.gwt.client.ui.VAudioPaintable;
/**
* The Audio component translates into an HTML5 &lt;audio&gt; element and as
@@ -28,7 +28,7 @@ import com.vaadin.terminal.gwt.client.ui.VAudio;
* @author Vaadin Ltd
* @since 6.7.0
*/
-@ClientWidget(VAudio.class)
+@ClientWidget(VAudioPaintable.class)
public class Audio extends AbstractMedia {
public Audio() {
diff --git a/src/com/vaadin/ui/BaseFieldFactory.java b/src/com/vaadin/ui/BaseFieldFactory.java
deleted file mode 100644
index fe271aabe4..0000000000
--- a/src/com/vaadin/ui/BaseFieldFactory.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.ui;
-
-import com.vaadin.data.Container;
-import com.vaadin.data.Item;
-import com.vaadin.data.Property;
-
-/**
- * Default implementation of the the following Field types are used by default:
- * <p>
- * <b>Boolean</b>: Button(switchMode:true).<br/>
- * <b>Date</b>: DateField(resolution: day).<br/>
- * <b>Item</b>: Form. <br/>
- * <b>default field type</b>: TextField.
- * <p>
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.1
- * @deprecated use {@link DefaultFieldFactory} or own implementations on
- * {@link FormFieldFactory} or {@link TableFieldFactory} instead.
- */
-
-@Deprecated
-@SuppressWarnings("serial")
-public class BaseFieldFactory implements FieldFactory {
-
- /**
- * Creates the field based on type of data.
- *
- *
- * @param type
- * the type of data presented in field.
- * @param uiContext
- * the context where the Field is presented.
- *
- * @see com.vaadin.ui.FieldFactory#createField(Class, Component)
- */
- public Field createField(Class<?> type, Component uiContext) {
- return DefaultFieldFactory.createFieldByPropertyType(type);
- }
-
- /**
- * Creates the field based on the datasource property.
- *
- * @see com.vaadin.ui.FieldFactory#createField(Property, Component)
- */
- public Field createField(Property property, Component uiContext) {
- if (property != null) {
- return createField(property.getType(), uiContext);
- } else {
- return null;
- }
- }
-
- /**
- * Creates the field based on the item and property id.
- *
- * @see com.vaadin.ui.FieldFactory#createField(Item, Object, Component)
- */
- public Field createField(Item item, Object propertyId, Component uiContext) {
- if (item != null && propertyId != null) {
- final Field f = createField(item.getItemProperty(propertyId),
- uiContext);
- if (f instanceof AbstractComponent) {
- String name = DefaultFieldFactory
- .createCaptionByPropertyId(propertyId);
- f.setCaption(name);
- }
- return f;
- } else {
- return null;
- }
- }
-
- /**
- * @see com.vaadin.ui.FieldFactory#createField(com.vaadin.data.Container,
- * java.lang.Object, java.lang.Object, com.vaadin.ui.Component)
- */
- public Field createField(Container container, Object itemId,
- Object propertyId, Component uiContext) {
- return createField(container.getContainerProperty(itemId, propertyId),
- uiContext);
- }
-
-}
diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java
index 795a13e41a..8f677a9775 100644
--- a/src/com/vaadin/ui/Button.java
+++ b/src/com/vaadin/ui/Button.java
@@ -9,7 +9,7 @@ import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Map;
-import com.vaadin.data.Property;
+import com.vaadin.event.Action;
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
@@ -23,8 +23,10 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.VButton;
+import com.vaadin.terminal.gwt.client.ui.VButtonPaintable;
+import com.vaadin.tools.ReflectTools;
import com.vaadin.ui.ClientWidget.LoadStyle;
-import com.vaadin.ui.themes.BaseTheme;
+import com.vaadin.ui.Component.Focusable;
/**
* A generic button component.
@@ -35,29 +37,23 @@ import com.vaadin.ui.themes.BaseTheme;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VButton.class, loadStyle = LoadStyle.EAGER)
-public class Button extends AbstractField implements FieldEvents.BlurNotifier,
- FieldEvents.FocusNotifier {
+@ClientWidget(value = VButtonPaintable.class, loadStyle = LoadStyle.EAGER)
+public class Button extends AbstractComponent implements
+ FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Focusable,
+ Action.ShortcutNotifier {
/* Private members */
- boolean switchMode = false;
-
boolean disableOnClick = false;
/**
- * Creates a new push button. The value of the push button is false and it
- * is immediate by default.
- *
+ * Creates a new push button.
*/
public Button() {
- setValue(Boolean.FALSE);
}
/**
- * Creates a new push button.
- *
- * The value of the push button is false and it is immediate by default.
+ * Creates a new push button with the given caption.
*
* @param caption
* the Button caption.
@@ -68,7 +64,7 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
}
/**
- * Creates a new push button with click listener.
+ * Creates a new push button with a click listener.
*
* @param caption
* the Button caption.
@@ -81,57 +77,6 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
}
/**
- * Creates a new push button with a method listening button clicks. Using
- * this method is discouraged because it cannot be checked during
- * compilation. Use
- * {@link #Button(String, com.vaadin.ui.Button.ClickListener)} instead. The
- * method must have either no parameters, or only one parameter of
- * Button.ClickEvent type.
- *
- * @param caption
- * the Button caption.
- * @param target
- * the Object having the method for listening button clicks.
- * @param methodName
- * the name of the method in target object, that receives button
- * click events.
- */
- public Button(String caption, Object target, String methodName) {
- this(caption);
- addListener(ClickEvent.class, target, methodName);
- }
-
- /**
- * Creates a new switch button with initial value.
- *
- * @param state
- * the Initial state of the switch-button.
- * @param initialState
- * @deprecated use {@link CheckBox} instead of Button in "switchmode"
- */
- @Deprecated
- public Button(String caption, boolean initialState) {
- setCaption(caption);
- setValue(Boolean.valueOf(initialState));
- setSwitchMode(true);
- }
-
- /**
- * Creates a new switch button that is connected to a boolean property.
- *
- * @param state
- * the Initial state of the switch-button.
- * @param dataSource
- * @deprecated use {@link CheckBox} instead of Button in "switchmode"
- */
- @Deprecated
- public Button(String caption, Property dataSource) {
- setCaption(caption);
- setSwitchMode(true);
- setPropertyDataSource(dataSource);
- }
-
- /**
* Paints the content of this component.
*
* @param event
@@ -145,11 +90,6 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
- if (isSwitchMode()) {
- target.addAttribute("type", "switch");
- }
- target.addVariable(this, "state", booleanValue());
-
if (isDisableOnClick()) {
target.addAttribute(VButton.ATTR_DISABLE_ON_CLICK, true);
}
@@ -176,46 +116,14 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
}
if (!isReadOnly() && variables.containsKey("state")) {
- // Gets the new and old button states
- final Boolean newValue = (Boolean) variables.get("state");
- final Boolean oldValue = (Boolean) getValue();
-
- if (isSwitchMode()) {
-
- // For switch button, the event is only sent if the
- // switch state is changed
- if (newValue != null && !newValue.equals(oldValue)
- && !isReadOnly()) {
- setValue(newValue);
- if (variables.containsKey("mousedetails")) {
- fireClick(MouseEventDetails
- .deSerialize((String) variables
- .get("mousedetails")));
- } else {
- // for compatibility with custom implementations which
- // don't send mouse details
- fireClick();
- }
- }
+ // Send click events when the button is pushed
+ if (variables.containsKey("mousedetails")) {
+ fireClick(MouseEventDetails.deSerialize((String) variables
+ .get("mousedetails")));
} else {
-
- // Only send click event if the button is pushed
- if (newValue.booleanValue()) {
- if (variables.containsKey("mousedetails")) {
- fireClick(MouseEventDetails
- .deSerialize((String) variables
- .get("mousedetails")));
- } else {
- // for compatibility with custom implementations which
- // don't send mouse details
- fireClick();
- }
- }
-
- // If the button is true for some reason, release it
- if (null == oldValue || oldValue.booleanValue()) {
- setValue(Boolean.FALSE);
- }
+ // for compatibility with custom implementations which
+ // don't send mouse details
+ fireClick();
}
}
@@ -228,92 +136,6 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
}
/**
- * Checks if it is switchMode.
- *
- * @return <code>true</code> if it is in Switch Mode, otherwise
- * <code>false</code>.
- * @deprecated the {@link CheckBox} component should be used instead of
- * Button in switch mode
- */
- @Deprecated
- public boolean isSwitchMode() {
- return switchMode;
- }
-
- /**
- * Sets the switchMode.
- *
- * @param switchMode
- * The switchMode to set.
- * @deprecated the {@link CheckBox} component should be used instead of
- * Button in switch mode
- */
- @Deprecated
- public void setSwitchMode(boolean switchMode) {
- this.switchMode = switchMode;
- if (!switchMode) {
- setImmediate(true);
- if (booleanValue()) {
- setValue(Boolean.FALSE);
- }
- }
- }
-
- /**
- * Get the boolean value of the button state.
- *
- * @return True iff the button is pressed down or checked.
- */
- public boolean booleanValue() {
- Boolean value = (Boolean) getValue();
- return (null == value) ? false : value.booleanValue();
- }
-
- /**
- * Sets immediate mode. Push buttons can not be set in non-immediate mode.
- *
- * @see com.vaadin.ui.AbstractComponent#setImmediate(boolean)
- */
- @Override
- public void setImmediate(boolean immediate) {
- // Push buttons are always immediate
- super.setImmediate(!isSwitchMode() || immediate);
- }
-
- /**
- * The type of the button as a property.
- *
- * @see com.vaadin.data.Property#getType()
- */
- @Override
- public Class getType() {
- return Boolean.class;
- }
-
- /* Click event */
-
- private static final Method BUTTON_CLICK_METHOD;
-
- /**
- * Button style with no decorations. Looks like a link, acts like a button
- *
- * @deprecated use {@link BaseTheme#BUTTON_LINK} instead.
- */
- @Deprecated
- public static final String STYLE_LINK = "link";
-
- static {
- try {
- BUTTON_CLICK_METHOD = ClickListener.class.getDeclaredMethod(
- "buttonClick", new Class[] { ClickEvent.class });
- } catch (final java.lang.NoSuchMethodException e) {
- // This should never happen
- throw new java.lang.RuntimeException(
- "Internal error finding methods in Button");
- }
- }
-
- /**
* Click event. This event is thrown, when the button is clicked.
*
* @author Vaadin Ltd.
@@ -484,6 +306,10 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
*/
public interface ClickListener extends Serializable {
+ public static final Method BUTTON_CLICK_METHOD = ReflectTools
+ .findMethod(ClickListener.class, "buttonClick",
+ ClickEvent.class);
+
/**
* Called when a {@link Button} has been clicked. A reference to the
* button is given by {@link ClickEvent#getButton()}.
@@ -502,7 +328,8 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
* the Listener to be added.
*/
public void addListener(ClickListener listener) {
- addListener(ClickEvent.class, listener, BUTTON_CLICK_METHOD);
+ addListener(ClickEvent.class, listener,
+ ClickListener.BUTTON_CLICK_METHOD);
}
/**
@@ -512,7 +339,8 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
* the Listener to be removed.
*/
public void removeListener(ClickListener listener) {
- removeListener(ClickEvent.class, listener, BUTTON_CLICK_METHOD);
+ removeListener(ClickEvent.class, listener,
+ ClickListener.BUTTON_CLICK_METHOD);
}
/**
@@ -538,16 +366,6 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
fireEvent(new Button.ClickEvent(this, details));
}
- @Override
- protected void setInternalValue(Object newValue) {
- // Make sure only booleans get through
- if (null != newValue && !(newValue instanceof Boolean)) {
- throw new IllegalArgumentException(getClass().getSimpleName()
- + " only accepts Boolean values");
- }
- super.setInternalValue(newValue);
- }
-
public void addListener(BlurListener listener) {
addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
BlurListener.blurMethod);
@@ -573,6 +391,8 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
protected ClickShortcut clickShortcut;
+ private int tabIndex = 0;
+
/**
* Makes it possible to invoke a click on this button by pressing the given
* {@link KeyCode} and (optional) {@link ModifierKey}s.<br/>
@@ -685,4 +505,18 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier,
requestRepaint();
}
+ public int getTabIndex() {
+ return tabIndex;
+ }
+
+ public void setTabIndex(int tabIndex) {
+ this.tabIndex = tabIndex;
+
+ }
+
+ @Override
+ public void focus() {
+ // Overridden only to make public
+ super.focus();
+ }
}
diff --git a/src/com/vaadin/ui/CheckBox.java b/src/com/vaadin/ui/CheckBox.java
index 00a248cdf3..9dc96bb55d 100644
--- a/src/com/vaadin/ui/CheckBox.java
+++ b/src/com/vaadin/ui/CheckBox.java
@@ -4,110 +4,130 @@
package com.vaadin.ui;
-import java.lang.reflect.Method;
+import java.util.Map;
import com.vaadin.data.Property;
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.gwt.client.ui.VCheckBox;
-@ClientWidget(com.vaadin.terminal.gwt.client.ui.VCheckBox.class)
-public class CheckBox extends Button {
+@ClientWidget(com.vaadin.terminal.gwt.client.ui.VCheckBoxPaintable.class)
+public class CheckBox extends AbstractField<Boolean> {
/**
- * Creates a new switch button.
+ * Creates a new checkbox.
*/
public CheckBox() {
- setSwitchMode(true);
+ setValue(Boolean.FALSE);
}
/**
- * Creates a new switch button with a caption and a set initial state.
+ * Creates a new checkbox with a set caption.
*
* @param caption
- * the caption of the switch button
- * @param initialState
- * the initial state of the switch button
+ * the Checkbox caption.
*/
- @SuppressWarnings("deprecation")
- public CheckBox(String caption, boolean initialState) {
- super(caption, initialState);
- }
-
- /**
- * Creates a new switch button with a caption and a click listener.
- *
- * @param caption
- * the caption of the switch button
- * @param listener
- * the click listener
- */
- public CheckBox(String caption, ClickListener listener) {
- super(caption, listener);
- setSwitchMode(true);
+ public CheckBox(String caption) {
+ this();
+ setCaption(caption);
}
/**
- * Convenience method for creating a new switch button with a method
- * listening button clicks. Using this method is discouraged because it
- * cannot be checked during compilation. Use
- * {@link #addListener(Class, Object, Method)} or
- * {@link #addListener(com.vaadin.ui.Component.Listener)} instead. The
- * method must have either no parameters, or only one parameter of
- * Button.ClickEvent type.
+ * Creates a new checkbox with a caption and a set initial state.
*
* @param caption
- * the Button caption.
- * @param target
- * the Object having the method for listening button clicks.
- * @param methodName
- * the name of the method in target object, that receives button
- * click events.
+ * the caption of the checkbox
+ * @param initialState
+ * the initial state of the checkbox
*/
- public CheckBox(String caption, Object target, String methodName) {
- super(caption, target, methodName);
- setSwitchMode(true);
+ public CheckBox(String caption, boolean initialState) {
+ this(caption);
+ setValue(initialState);
}
/**
- * Creates a new switch button that is connected to a boolean property.
+ * Creates a new checkbox that is connected to a boolean property.
*
* @param state
* the Initial state of the switch-button.
* @param dataSource
*/
- @SuppressWarnings("deprecation")
- public CheckBox(String caption, Property dataSource) {
- super(caption, dataSource);
- setSwitchMode(true);
+ public CheckBox(String caption, Property<?> dataSource) {
+ this(caption);
+ setPropertyDataSource(dataSource);
}
- /**
- * Creates a new push button with a set caption.
- *
- * The value of the push button is always false and they are immediate by
- * default.
- *
- * @param caption
- * the Button caption.
- */
+ @Override
+ public Class<Boolean> getType() {
+ return Boolean.class;
+ }
- @SuppressWarnings("deprecation")
- public CheckBox(String caption) {
- super(caption, false);
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+
+ Boolean value = getValue();
+ boolean booleanValue = (value != null) ? value : false;
+ target.addVariable(this, VCheckBox.VARIABLE_STATE, booleanValue);
}
- @Deprecated
@Override
- public void setSwitchMode(boolean switchMode)
- throws UnsupportedOperationException {
- if (this.switchMode && !switchMode) {
- throw new UnsupportedOperationException(
- "CheckBox is always in switch mode (consider using a Button)");
+ public void changeVariables(Object source, Map<String, Object> variables) {
+ super.changeVariables(source, variables);
+
+ if (!isReadOnly() && variables.containsKey(VCheckBox.VARIABLE_STATE)) {
+ // Gets the new and old states
+ final Boolean newValue = (Boolean) variables
+ .get(VCheckBox.VARIABLE_STATE);
+ final Boolean oldValue = getValue();
+
+ // The event is only sent if the switch state is changed
+ if (newValue != null && !newValue.equals(oldValue)) {
+ setValue(newValue);
+ }
+ }
+
+ if (variables.containsKey(FocusEvent.EVENT_ID)) {
+ fireEvent(new FocusEvent(this));
+ }
+ if (variables.containsKey(BlurEvent.EVENT_ID)) {
+ fireEvent(new BlurEvent(this));
}
- super.setSwitchMode(true);
}
- @Override
- public void setDisableOnClick(boolean disableOnClick) {
- throw new UnsupportedOperationException(
- "CheckBox does not support disable on click");
+ public void addListener(BlurListener listener) {
+ addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ }
+
+ public void removeListener(BlurListener listener) {
+ removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+ }
+
+ public void addListener(FocusListener listener) {
+ addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+ FocusListener.focusMethod);
}
+ public void removeListener(FocusListener listener) {
+ removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+
+ }
+
+ /**
+ * Get the boolean value of the button state.
+ *
+ * @return True iff the button is pressed down or checked.
+ *
+ * @deprecated Use {@link #getValue()} instead and, if needed, handle null
+ * values.
+ */
+ @Deprecated
+ public boolean booleanValue() {
+ Boolean value = getValue();
+ return (null == value) ? false : value.booleanValue();
+ }
}
diff --git a/src/com/vaadin/ui/ClientWidget.java b/src/com/vaadin/ui/ClientWidget.java
index 8817f8f776..d944e8b3c8 100644
--- a/src/com/vaadin/ui/ClientWidget.java
+++ b/src/com/vaadin/ui/ClientWidget.java
@@ -11,7 +11,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
import com.vaadin.terminal.gwt.widgetsetutils.CustomWidgetMapGenerator;
import com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator;
import com.vaadin.terminal.gwt.widgetsetutils.LazyWidgetMapGenerator;
@@ -36,7 +36,7 @@ public @interface ClientWidget {
/**
* @return the client side counterpart for the annotated component
*/
- Class<? extends Paintable> value();
+ Class<? extends VPaintableWidget> value();
/**
* Depending on the used WidgetMap generator, these optional hints may be
diff --git a/src/com/vaadin/ui/ComboBox.java b/src/com/vaadin/ui/ComboBox.java
index bc7ab6f994..013fe6ab85 100644
--- a/src/com/vaadin/ui/ComboBox.java
+++ b/src/com/vaadin/ui/ComboBox.java
@@ -10,6 +10,7 @@ import com.vaadin.data.Container;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
+import com.vaadin.terminal.gwt.client.ui.VFilterSelectPaintable;
/**
* A filtering dropdown single-select. Suitable for newItemsAllowed, but it's
@@ -20,7 +21,7 @@ import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
*
*/
@SuppressWarnings("serial")
-@ClientWidget(VFilterSelect.class)
+@ClientWidget(VFilterSelectPaintable.class)
public class ComboBox extends Select {
private String inputPrompt = null;
diff --git a/src/com/vaadin/ui/Component.java b/src/com/vaadin/ui/Component.java
index b32aad2fca..1289b57bd9 100644
--- a/src/com/vaadin/ui/Component.java
+++ b/src/com/vaadin/ui/Component.java
@@ -560,7 +560,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable,
* @return the parent window of the component or <code>null</code> if it is
* not attached to a window or is itself a window
*/
- public Window getWindow();
+ public Root getRoot();
/**
* Gets the application object to which the component is attached.
@@ -593,7 +593,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable,
* <p>
* Reimplementing the {@code attach()} method is useful for tasks that need
* to get a reference to the parent, window, or application object with the
- * {@link #getParent()}, {@link #getWindow()}, and {@link #getApplication()}
+ * {@link #getParent()}, {@link #getRoot()}, and {@link #getApplication()}
* methods. A component does not yet know these objects in the constructor,
* so in such case, the methods will return {@code null}. For example, the
* following is invalid:
@@ -648,7 +648,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable,
* Notifies the component that it is detached from the application.
*
* <p>
- * The {@link #getApplication()} and {@link #getWindow()} methods might
+ * The {@link #getApplication()} and {@link #getRoot()} methods might
* return <code>null</code> after this method is called.
* </p>
*
diff --git a/src/com/vaadin/ui/CssLayout.java b/src/com/vaadin/ui/CssLayout.java
index b9432df6b6..ebfee5a787 100644
--- a/src/com/vaadin/ui/CssLayout.java
+++ b/src/com/vaadin/ui/CssLayout.java
@@ -14,7 +14,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Paintable;
import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.ui.VCssLayout;
+import com.vaadin.terminal.gwt.client.ui.VCssLayoutPaintable;
/**
* CssLayout is a layout component that can be used in browser environment only.
@@ -57,7 +57,7 @@ import com.vaadin.terminal.gwt.client.ui.VCssLayout;
* @since 6.1 brought in from "FastLayouts" incubator project
*
*/
-@ClientWidget(VCssLayout.class)
+@ClientWidget(VCssLayoutPaintable.class)
public class CssLayout extends AbstractLayout implements LayoutClickNotifier {
private static final String CLICK_EVENT = EventId.LAYOUT_CLICK;
diff --git a/src/com/vaadin/ui/CustomComponent.java b/src/com/vaadin/ui/CustomComponent.java
index 21eda08909..7aba34b6bb 100644
--- a/src/com/vaadin/ui/CustomComponent.java
+++ b/src/com/vaadin/ui/CustomComponent.java
@@ -9,7 +9,7 @@ import java.util.Iterator;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VCustomComponent;
+import com.vaadin.terminal.gwt.client.ui.VCustomComponentPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -27,7 +27,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VCustomComponent.class, loadStyle = LoadStyle.EAGER)
+@ClientWidget(value = VCustomComponentPaintable.class, loadStyle = LoadStyle.EAGER)
public class CustomComponent extends AbstractComponentContainer {
/**
@@ -36,11 +36,6 @@ public class CustomComponent extends AbstractComponentContainer {
private Component root = null;
/**
- * Type of the component.
- */
- private String componentType = null;
-
- /**
* Constructs a new custom component.
*
* <p>
@@ -115,43 +110,9 @@ public class CustomComponent extends AbstractComponentContainer {
+ " can be painted");
}
- if (getComponentType() != null) {
- target.addAttribute("type", getComponentType());
- }
root.paint(target);
}
- /**
- * Gets the component type.
- *
- * The component type is textual type of the component. This is included in
- * the UIDL as component tag attribute.
- *
- * @deprecated not more useful as the whole tag system has been removed
- *
- * @return the component type.
- */
- @Deprecated
- public String getComponentType() {
- return componentType;
- }
-
- /**
- * Sets the component type.
- *
- * The component type is textual type of the component. This is included in
- * the UIDL as component tag attribute.
- *
- * @deprecated not more useful as the whole tag system has been removed
- *
- * @param componentType
- * the componentType to set.
- */
- @Deprecated
- public void setComponentType(String componentType) {
- this.componentType = componentType;
- }
-
private class ComponentIterator implements Iterator<Component>,
Serializable {
boolean first = getCompositionRoot() != null;
diff --git a/src/com/vaadin/ui/CustomField.java b/src/com/vaadin/ui/CustomField.java
new file mode 100644
index 0000000000..73f9050363
--- /dev/null
+++ b/src/com/vaadin/ui/CustomField.java
@@ -0,0 +1,252 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+
+import com.vaadin.data.Property;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.gwt.client.ui.VCustomComponentPaintable;
+
+/**
+ * A {@link Field} whose UI content can be constructed by the user, enabling the
+ * creation of e.g. form fields by composing Vaadin components. Customization of
+ * both the visual presentation and the logic of the field is possible.
+ *
+ * Subclasses must implement {@link #getType()} and {@link #initContent()}.
+ *
+ * Most custom fields can simply compose a user interface that calls the methods
+ * {@link #setInternalValue(Object)} and {@link #getInternalValue()} when
+ * necessary.
+ *
+ * It is also possible to override {@link #validate()},
+ * {@link #setInternalValue(Object)}, {@link #commit()},
+ * {@link #setPropertyDataSource(Property)}, {@link #isEmpty()} and other logic
+ * of the field. Methods overriding {@link #setInternalValue(Object)} should
+ * also call the corresponding superclass method.
+ *
+ * @param <T>
+ * field value type
+ *
+ * @since 7.0
+ */
+@ClientWidget(VCustomComponentPaintable.class)
+public abstract class CustomField<T> extends AbstractField<T> implements
+ ComponentContainer {
+
+ /**
+ * The root component implementing the custom component.
+ */
+ private Component root = null;
+
+ /**
+ * Constructs a new custom field.
+ *
+ * <p>
+ * The component is implemented by wrapping the methods of the composition
+ * root component given as parameter. The composition root must be set
+ * before the component can be used.
+ * </p>
+ */
+ public CustomField() {
+ // expand horizontally by default
+ setWidth(100, Unit.PERCENTAGE);
+ }
+
+ /**
+ * Constructs the content and notifies it that the {@link CustomField} is
+ * attached to a window.
+ *
+ * @see com.vaadin.ui.Component#attach()
+ */
+ @Override
+ public void attach() {
+ root = getContent();
+ super.attach();
+ getContent().setParent(this);
+ getContent().attach();
+
+ fireComponentAttachEvent(getContent());
+ }
+
+ /**
+ * Notifies the content that the {@link CustomField} is detached from a
+ * window.
+ *
+ * @see com.vaadin.ui.Component#detach()
+ */
+ @Override
+ public void detach() {
+ super.detach();
+ getContent().detach();
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ if (getContent() == null) {
+ throw new IllegalStateException(
+ "Content component or layout of the field must be set before the "
+ + getClass().getName() + " can be painted");
+ }
+
+ getContent().paint(target);
+ }
+
+ /**
+ * Returns the content (UI) of the custom component.
+ *
+ * @return Component
+ */
+ protected Component getContent() {
+ if (null == root) {
+ root = initContent();
+ }
+ return root;
+ }
+
+ /**
+ * Create the content component or layout for the field. Subclasses of
+ * {@link CustomField} should implement this method.
+ *
+ * Note that this method is called when the CustomField is attached to a
+ * layout or when {@link #getContent()} is called explicitly for the first
+ * time. It is only called once for a {@link CustomField}.
+ *
+ * @return {@link Component} representing the UI of the CustomField
+ */
+ protected abstract Component initContent();
+
+ private void requestContentRepaint() {
+ if (getParent() == null) {
+ // skip repaint - not yet attached
+ return;
+ }
+ if (getContent() instanceof ComponentContainer) {
+ ((ComponentContainer) getContent()).requestRepaintAll();
+ } else {
+ getContent().requestRepaint();
+ }
+ }
+
+ // Size related methods
+ // TODO might not be necessary to override but following the pattern from
+ // AbstractComponentContainer
+
+ @Override
+ public void setHeight(float height, Unit unit) {
+ super.setHeight(height, unit);
+ requestContentRepaint();
+ }
+
+ @Override
+ public void setWidth(float height, Unit unit) {
+ super.setWidth(height, unit);
+ requestContentRepaint();
+ }
+
+ // ComponentContainer methods
+
+ private class ComponentIterator implements Iterator<Component>,
+ Serializable {
+ boolean first = getContent() != null;
+
+ public boolean hasNext() {
+ return first;
+ }
+
+ public Component next() {
+ first = false;
+ return getContent();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public Iterator<Component> getComponentIterator() {
+ return new ComponentIterator();
+ }
+
+ public int getComponentCount() {
+ return (null != getContent()) ? 1 : 0;
+ }
+
+ public void requestRepaintAll() {
+ requestRepaint();
+
+ requestContentRepaint();
+ }
+
+ /**
+ * Fires the component attached event. This should be called by the
+ * addComponent methods after the component have been added to this
+ * container.
+ *
+ * @param component
+ * the component that has been added to this container.
+ */
+ protected void fireComponentAttachEvent(Component component) {
+ fireEvent(new ComponentAttachEvent(this, component));
+ }
+
+ // TODO remove these methods when ComponentContainer interface is cleaned up
+
+ public void addComponent(Component c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeComponent(Component c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeAllComponents() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void replaceComponent(Component oldComponent, Component newComponent) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void moveComponentsFrom(ComponentContainer source) {
+ throw new UnsupportedOperationException();
+ }
+
+ private static final Method COMPONENT_ATTACHED_METHOD;
+
+ static {
+ try {
+ COMPONENT_ATTACHED_METHOD = ComponentAttachListener.class
+ .getDeclaredMethod("componentAttachedToContainer",
+ new Class[] { ComponentAttachEvent.class });
+ } catch (final java.lang.NoSuchMethodException e) {
+ // This should never happen
+ throw new java.lang.RuntimeException(
+ "Internal error finding methods in CustomField");
+ }
+ }
+
+ public void addListener(ComponentAttachListener listener) {
+ addListener(ComponentContainer.ComponentAttachEvent.class, listener,
+ COMPONENT_ATTACHED_METHOD);
+ }
+
+ public void removeListener(ComponentAttachListener listener) {
+ removeListener(ComponentContainer.ComponentAttachEvent.class, listener,
+ COMPONENT_ATTACHED_METHOD);
+ }
+
+ public void addListener(ComponentDetachListener listener) {
+ // content never detached
+ }
+
+ public void removeListener(ComponentDetachListener listener) {
+ // content never detached
+ }
+
+}
diff --git a/src/com/vaadin/ui/CustomLayout.java b/src/com/vaadin/ui/CustomLayout.java
index dc473fb549..fb0c369969 100644
--- a/src/com/vaadin/ui/CustomLayout.java
+++ b/src/com/vaadin/ui/CustomLayout.java
@@ -12,7 +12,7 @@ import java.util.Iterator;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VCustomLayout;
+import com.vaadin.terminal.gwt.client.ui.VCustomLayoutPaintable;
/**
* <p>
@@ -44,7 +44,7 @@ import com.vaadin.terminal.gwt.client.ui.VCustomLayout;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VCustomLayout.class)
+@ClientWidget(VCustomLayoutPaintable.class)
public class CustomLayout extends AbstractLayout {
private static final int BUFFER_SIZE = 10000;
diff --git a/src/com/vaadin/ui/DateField.java b/src/com/vaadin/ui/DateField.java
index ef67345aab..9589414f4d 100644
--- a/src/com/vaadin/ui/DateField.java
+++ b/src/com/vaadin/ui/DateField.java
@@ -4,11 +4,13 @@
package com.vaadin.ui;
-import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
@@ -16,6 +18,7 @@ import java.util.TimeZone;
import com.vaadin.data.Property;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
+import com.vaadin.data.util.converter.Converter;
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
@@ -24,7 +27,7 @@ import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VDateField;
-import com.vaadin.terminal.gwt.client.ui.VPopupCalendar;
+import com.vaadin.terminal.gwt.client.ui.VPopupCalendarPaintable;
/**
* <p>
@@ -47,56 +50,129 @@ import com.vaadin.terminal.gwt.client.ui.VPopupCalendar;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VPopupCalendar.class)
-public class DateField extends AbstractField implements
+@ClientWidget(VPopupCalendarPaintable.class)
+public class DateField extends AbstractField<Date> implements
FieldEvents.BlurNotifier, FieldEvents.FocusNotifier {
- /* Private members */
-
/**
- * Resolution identifier: milliseconds.
+ * Resolutions for DateFields
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
*/
- public static final int RESOLUTION_MSEC = 0;
+ public enum Resolution {
+ SECOND(Calendar.SECOND), MINUTE(Calendar.MINUTE), HOUR(
+ Calendar.HOUR_OF_DAY), DAY(Calendar.DAY_OF_MONTH), MONTH(
+ Calendar.MONTH), YEAR(Calendar.YEAR);
+
+ private int calendarField;
+
+ private Resolution(int calendarField) {
+ this.calendarField = calendarField;
+ }
+
+ /**
+ * Returns the field in {@link Calendar} that corresponds to this
+ * resolution.
+ *
+ * @return one of the field numbers used by Calendar
+ */
+ public int getCalendarField() {
+ return calendarField;
+ }
+
+ /**
+ * Returns the resolutions that are higher or equal to the given
+ * resolution, starting from the given resolution. In other words
+ * passing DAY to this methods returns DAY,MONTH,YEAR
+ *
+ * @param r
+ * The resolution to start from
+ * @return An iterable for the resolutions higher or equal to r
+ */
+ public static Iterable<Resolution> getResolutionsHigherOrEqualTo(
+ Resolution r) {
+ List<Resolution> resolutions = new ArrayList<DateField.Resolution>();
+ Resolution[] values = Resolution.values();
+ for (int i = r.ordinal(); i < values.length; i++) {
+ resolutions.add(values[i]);
+ }
+ return resolutions;
+ }
+
+ /**
+ * Returns the resolutions that are lower than the given resolution,
+ * starting from the given resolution. In other words passing DAY to
+ * this methods returns HOUR,MINUTE,SECOND.
+ *
+ * @param r
+ * The resolution to start from
+ * @return An iterable for the resolutions lower than r
+ */
+ public static List<Resolution> getResolutionsLowerThan(Resolution r) {
+ List<Resolution> resolutions = new ArrayList<DateField.Resolution>();
+ Resolution[] values = Resolution.values();
+ for (int i = r.ordinal() - 1; i >= 0; i--) {
+ resolutions.add(values[i]);
+ }
+ return resolutions;
+ }
+ };
/**
* Resolution identifier: seconds.
+ *
+ * @deprecated Use {@link Resolution#SECOND}
*/
- public static final int RESOLUTION_SEC = 1;
+ @Deprecated
+ public static final Resolution RESOLUTION_SEC = Resolution.SECOND;
/**
* Resolution identifier: minutes.
+ *
+ * @deprecated Use {@link Resolution#MINUTE}
*/
- public static final int RESOLUTION_MIN = 2;
+ @Deprecated
+ public static final Resolution RESOLUTION_MIN = Resolution.MINUTE;
/**
* Resolution identifier: hours.
+ *
+ * @deprecated Use {@link Resolution#HOUR}
*/
- public static final int RESOLUTION_HOUR = 3;
+ @Deprecated
+ public static final Resolution RESOLUTION_HOUR = Resolution.HOUR;
/**
* Resolution identifier: days.
+ *
+ * @deprecated Use {@link Resolution#DAY}
*/
- public static final int RESOLUTION_DAY = 4;
+ @Deprecated
+ public static final Resolution RESOLUTION_DAY = Resolution.DAY;
/**
* Resolution identifier: months.
+ *
+ * @deprecated Use {@link Resolution#MONTH}
*/
- public static final int RESOLUTION_MONTH = 5;
+ @Deprecated
+ public static final Resolution RESOLUTION_MONTH = Resolution.MONTH;
/**
* Resolution identifier: years.
+ *
+ * @deprecated Use {@link Resolution#YEAR}
*/
- public static final int RESOLUTION_YEAR = 6;
-
- /**
- * Specified smallest modifiable unit.
- */
- private int resolution = RESOLUTION_MSEC;
+ @Deprecated
+ public static final Resolution RESOLUTION_YEAR = Resolution.YEAR;
/**
- * Specified largest modifiable unit.
+ * Specified smallest modifiable unit for the date field.
*/
- private static final int largestModifiable = RESOLUTION_YEAR;
+ private Resolution resolution = Resolution.DAY;
/**
* The internal calendar to be used in java.utl.Date conversions.
@@ -129,6 +205,16 @@ public class DateField extends AbstractField implements
private TimeZone timeZone = null;
+ private static Map<Resolution, String> variableNameForResolution = new HashMap<DateField.Resolution, String>();
+ {
+ variableNameForResolution.put(Resolution.SECOND, "sec");
+ variableNameForResolution.put(Resolution.MINUTE, "min");
+ variableNameForResolution.put(Resolution.HOUR, "hour");
+ variableNameForResolution.put(Resolution.DAY, "day");
+ variableNameForResolution.put(Resolution.MONTH, "month");
+ variableNameForResolution.put(Resolution.YEAR, "year");
+ }
+
/* Constructors */
/**
@@ -228,51 +314,21 @@ public class DateField extends AbstractField implements
// Gets the calendar
final Calendar calendar = getCalendar();
- final Date currentDate = (Date) getValue();
-
- for (int r = resolution; r <= largestModifiable; r++) {
- switch (r) {
- case RESOLUTION_MSEC:
- target.addVariable(
- this,
- "msec",
- currentDate != null ? calendar
- .get(Calendar.MILLISECOND) : -1);
- break;
- case RESOLUTION_SEC:
- target.addVariable(this, "sec",
- currentDate != null ? calendar.get(Calendar.SECOND)
- : -1);
- break;
- case RESOLUTION_MIN:
- target.addVariable(this, "min",
- currentDate != null ? calendar.get(Calendar.MINUTE)
- : -1);
- break;
- case RESOLUTION_HOUR:
- target.addVariable(
- this,
- "hour",
- currentDate != null ? calendar
- .get(Calendar.HOUR_OF_DAY) : -1);
- break;
- case RESOLUTION_DAY:
- target.addVariable(
- this,
- "day",
- currentDate != null ? calendar
- .get(Calendar.DAY_OF_MONTH) : -1);
- break;
- case RESOLUTION_MONTH:
- target.addVariable(this, "month",
- currentDate != null ? calendar.get(Calendar.MONTH) + 1
- : -1);
- break;
- case RESOLUTION_YEAR:
- target.addVariable(this, "year",
- currentDate != null ? calendar.get(Calendar.YEAR) : -1);
- break;
+ final Date currentDate = getValue();
+
+ // Only paint variables for the resolution and up, e.g. Resolution DAY
+ // paints DAY,MONTH,YEAR
+ for (Resolution res : Resolution
+ .getResolutionsHigherOrEqualTo(resolution)) {
+ int value = -1;
+ if (currentDate != null) {
+ value = calendar.get(res.getCalendarField());
+ if (res == Resolution.MONTH) {
+ // Calendar month is zero based
+ value++;
+ }
}
+ target.addVariable(this, variableNameForResolution.get(res), value);
}
}
@@ -298,10 +354,10 @@ public class DateField extends AbstractField implements
|| variables.containsKey("min")
|| variables.containsKey("sec")
|| variables.containsKey("msec") || variables
- .containsKey("dateString"))) {
+ .containsKey("dateString"))) {
// Old and new dates
- final Date oldDate = (Date) getValue();
+ final Date oldDate = getValue();
Date newDate = null;
// this enables analyzing invalid input on the server
@@ -309,59 +365,50 @@ public class DateField extends AbstractField implements
dateString = newDateString;
// Gets the new date in parts
- // Null values are converted to negative values.
- int year = variables.containsKey("year") ? (variables.get("year") == null ? -1
- : ((Integer) variables.get("year")).intValue())
- : -1;
- int month = variables.containsKey("month") ? (variables
- .get("month") == null ? -1 : ((Integer) variables
- .get("month")).intValue() - 1) : -1;
- int day = variables.containsKey("day") ? (variables.get("day") == null ? -1
- : ((Integer) variables.get("day")).intValue())
- : -1;
- int hour = variables.containsKey("hour") ? (variables.get("hour") == null ? -1
- : ((Integer) variables.get("hour")).intValue())
- : -1;
- int min = variables.containsKey("min") ? (variables.get("min") == null ? -1
- : ((Integer) variables.get("min")).intValue())
- : -1;
- int sec = variables.containsKey("sec") ? (variables.get("sec") == null ? -1
- : ((Integer) variables.get("sec")).intValue())
- : -1;
- int msec = variables.containsKey("msec") ? (variables.get("msec") == null ? -1
- : ((Integer) variables.get("msec")).intValue())
- : -1;
-
- // If all of the components is < 0 use the previous value
- if (year < 0 && month < 0 && day < 0 && hour < 0 && min < 0
- && sec < 0 && msec < 0) {
+ boolean hasChanges = false;
+ Map<Resolution, Integer> calendarFieldChanges = new HashMap<DateField.Resolution, Integer>();
+
+ for (Resolution r : Resolution
+ .getResolutionsHigherOrEqualTo(resolution)) {
+ // Only handle what the client is allowed to send. The same
+ // resolutions that are painted
+ String variableName = variableNameForResolution.get(r);
+
+ if (variables.containsKey(variableName)) {
+ Integer value = (Integer) variables.get(variableName);
+ if (r == Resolution.MONTH) {
+ // Calendar MONTH is zero based
+ value--;
+ }
+ if (value >= 0) {
+ hasChanges = true;
+ calendarFieldChanges.put(r, value);
+ }
+ }
+ }
+
+ // If no new variable values were received, use the previous value
+ if (!hasChanges) {
newDate = null;
} else {
-
// Clone the calendar for date operation
final Calendar cal = getCalendar();
- // Make sure that meaningful values exists
- // Use the previous value if some of the variables
- // have not been changed.
- year = year < 0 ? cal.get(Calendar.YEAR) : year;
- month = month < 0 ? cal.get(Calendar.MONTH) : month;
- day = day < 0 ? cal.get(Calendar.DAY_OF_MONTH) : day;
- hour = hour < 0 ? cal.get(Calendar.HOUR_OF_DAY) : hour;
- min = min < 0 ? cal.get(Calendar.MINUTE) : min;
- sec = sec < 0 ? cal.get(Calendar.SECOND) : sec;
- msec = msec < 0 ? cal.get(Calendar.MILLISECOND) : msec;
-
- // Sets the calendar fields
- cal.set(Calendar.YEAR, year);
- cal.set(Calendar.MONTH, month);
- cal.set(Calendar.DAY_OF_MONTH, day);
- cal.set(Calendar.HOUR_OF_DAY, hour);
- cal.set(Calendar.MINUTE, min);
- cal.set(Calendar.SECOND, sec);
- cal.set(Calendar.MILLISECOND, msec);
-
- // Assigns the date
+ // Update the value based on the received info
+ // Must set in this order to avoid invalid dates (or wrong
+ // dates if lenient is true) in calendar
+ for (int r = Resolution.YEAR.ordinal(); r >= 0; r--) {
+ Resolution res = Resolution.values()[r];
+ if (calendarFieldChanges.containsKey(res)) {
+
+ // Field resolution should be included. Others are
+ // skipped so that client can not make unexpected
+ // changes (e.g. day change even though resolution is
+ // year).
+ Integer newValue = calendarFieldChanges.get(res);
+ cal.set(res.getCalendarField(), newValue);
+ }
+ }
newDate = cal.getTime();
}
@@ -377,7 +424,7 @@ public class DateField extends AbstractField implements
* this case the invalid text remains in the DateField.
*/
requestRepaint();
- } catch (ConversionException e) {
+ } catch (Converter.ConversionException e) {
/*
* Datefield now contains some text that could't be parsed
@@ -445,7 +492,7 @@ public class DateField extends AbstractField implements
* This method is called to handle a non-empty date string from the client
* if the client could not parse it as a Date.
*
- * By default, a Property.ConversionException is thrown, and the current
+ * By default, a Converter.ConversionException is thrown, and the current
* value is not modified.
*
* This can be overridden to handle conversions, to return null (equivalent
@@ -453,13 +500,13 @@ public class DateField extends AbstractField implements
*
* @param dateString
* @return parsed Date
- * @throws Property.ConversionException
+ * @throws Converter.ConversionException
* to keep the old value and indicate an error
*/
protected Date handleUnparsableDateString(String dateString)
- throws Property.ConversionException {
+ throws Converter.ConversionException {
currentParseErrorMessage = null;
- throw new Property.ConversionException(getParseErrorMessage());
+ throw new Converter.ConversionException(getParseErrorMessage());
}
/* Property features */
@@ -469,7 +516,7 @@ public class DateField extends AbstractField implements
* the default documentation from implemented interface.
*/
@Override
- public Class<?> getType() {
+ public Class<Date> getType() {
return Date.class;
}
@@ -479,8 +526,8 @@ public class DateField extends AbstractField implements
* @see com.vaadin.ui.AbstractField#setValue(java.lang.Object, boolean)
*/
@Override
- protected void setValue(Object newValue, boolean repaintIsNotNeeded)
- throws Property.ReadOnlyException, Property.ConversionException {
+ protected void setValue(Date newValue, boolean repaintIsNotNeeded)
+ throws Property.ReadOnlyException {
/*
* First handle special case when the client side component have a date
@@ -513,23 +560,7 @@ public class DateField extends AbstractField implements
return;
}
- if (newValue == null || newValue instanceof Date) {
- super.setValue(newValue, repaintIsNotNeeded);
- } else {
- // Try to parse the given string value to Date
- try {
- final SimpleDateFormat parser = new SimpleDateFormat();
- final TimeZone currentTimeZone = getTimeZone();
- if (currentTimeZone != null) {
- parser.setTimeZone(currentTimeZone);
- }
- final Date val = parser.parse(newValue.toString());
- super.setValue(val, repaintIsNotNeeded);
- } catch (final ParseException e) {
- uiHasValidDateString = false;
- throw new Property.ConversionException(getParseErrorMessage());
- }
- }
+ super.setValue(newValue, repaintIsNotNeeded);
}
/**
@@ -544,7 +575,7 @@ public class DateField extends AbstractField implements
Form f = (Form) parenOfDateField;
Collection<?> visibleItemProperties = f.getItemPropertyIds();
for (Object fieldId : visibleItemProperties) {
- Field field = f.getField(fieldId);
+ Field<?> field = f.getField(fieldId);
if (field == this) {
/*
* this datefield is logically in a form. Do the same
@@ -564,24 +595,8 @@ public class DateField extends AbstractField implements
}
}
- /**
- * Sets the DateField datasource. Datasource type must assignable to Date.
- *
- * @see com.vaadin.data.Property.Viewer#setPropertyDataSource(Property)
- */
@Override
- public void setPropertyDataSource(Property newDataSource) {
- if (newDataSource == null
- || Date.class.isAssignableFrom(newDataSource.getType())) {
- super.setPropertyDataSource(newDataSource);
- } else {
- throw new IllegalArgumentException(
- "DateField only supports Date properties");
- }
- }
-
- @Override
- protected void setInternalValue(Object newValue) {
+ protected void setInternalValue(Date newValue) {
// Also set the internal dateString
if (newValue != null) {
dateString = newValue.toString();
@@ -604,17 +619,19 @@ public class DateField extends AbstractField implements
*
* @return int
*/
- public int getResolution() {
+ public Resolution getResolution() {
return resolution;
}
/**
* Sets the resolution of the DateField.
*
+ * The default resolution is {@link Resolution#DAY} since Vaadin 7.0.
+ *
* @param resolution
* the resolution to set.
*/
- public void setResolution(int resolution) {
+ public void setResolution(Resolution resolution) {
this.resolution = resolution;
requestRepaint();
}
@@ -636,13 +653,19 @@ public class DateField extends AbstractField implements
// Makes sure we have an calendar instance
if (calendar == null) {
calendar = Calendar.getInstance();
+ // Start by a zeroed calendar to avoid having values for lower
+ // resolution variables e.g. time when resolution is day
+ for (Resolution r : Resolution.getResolutionsLowerThan(resolution)) {
+ calendar.set(r.getCalendarField(), 0);
+ }
+ calendar.set(Calendar.MILLISECOND, 0);
}
// Clone the instance
final Calendar newCal = (Calendar) calendar.clone();
// Assigns the current time tom calendar.
- final Date currentDate = (Date) getValue();
+ final Date currentDate = getValue();
if (currentDate != null) {
newCal.setTime(currentDate);
}
@@ -752,19 +775,14 @@ public class DateField extends AbstractField implements
}
/**
- * Tests the current value against registered validators if the field is not
- * empty. Note that DateField is considered empty (value == null) and
+ * Validates the current value against registered validators if the field is
+ * not empty. Note that DateField is considered empty (value == null) and
* invalid if it contains text typed in by the user that couldn't be parsed
* into a Date value.
*
- * @see com.vaadin.ui.AbstractField#isValid()
+ * @see com.vaadin.ui.AbstractField#validate()
*/
@Override
- public boolean isValid() {
- return uiHasValidDateString && super.isValid();
- }
-
- @Override
public void validate() throws InvalidValueException {
/*
* To work properly in form we must throw exception if there is
diff --git a/src/com/vaadin/ui/DefaultFieldFactory.java b/src/com/vaadin/ui/DefaultFieldFactory.java
index 1e55d2795f..9d096094e3 100644
--- a/src/com/vaadin/ui/DefaultFieldFactory.java
+++ b/src/com/vaadin/ui/DefaultFieldFactory.java
@@ -35,19 +35,20 @@ public class DefaultFieldFactory implements FormFieldFactory, TableFieldFactory
protected DefaultFieldFactory() {
}
- public Field createField(Item item, Object propertyId, Component uiContext) {
+ public Field<?> createField(Item item, Object propertyId,
+ Component uiContext) {
Class<?> type = item.getItemProperty(propertyId).getType();
- Field field = createFieldByPropertyType(type);
+ Field<?> field = createFieldByPropertyType(type);
field.setCaption(createCaptionByPropertyId(propertyId));
return field;
}
- public Field createField(Container container, Object itemId,
+ public Field<?> createField(Container container, Object itemId,
Object propertyId, Component uiContext) {
- Property containerProperty = container.getContainerProperty(itemId,
+ Property<?> containerProperty = container.getContainerProperty(itemId,
propertyId);
Class<?> type = containerProperty.getType();
- Field field = createFieldByPropertyType(type);
+ Field<?> field = createFieldByPropertyType(type);
field.setCaption(createCaptionByPropertyId(propertyId));
return field;
}
@@ -63,6 +64,10 @@ public class DefaultFieldFactory implements FormFieldFactory, TableFieldFactory
String name = propertyId.toString();
if (name.length() > 0) {
+ int dotLocation = name.lastIndexOf('.');
+ if (dotLocation > 0 && dotLocation < name.length() - 1) {
+ name = name.substring(dotLocation + 1);
+ }
if (name.indexOf(' ') < 0
&& name.charAt(0) == Character.toLowerCase(name.charAt(0))
&& name.charAt(0) != Character.toUpperCase(name.charAt(0))) {
@@ -110,7 +115,7 @@ public class DefaultFieldFactory implements FormFieldFactory, TableFieldFactory
* the type of the property
* @return the most suitable generic {@link Field} for given type
*/
- public static Field createFieldByPropertyType(Class<?> type) {
+ public static Field<?> createFieldByPropertyType(Class<?> type) {
// Null typed properties can not be edited
if (type == null) {
return null;
diff --git a/src/com/vaadin/ui/DragAndDropWrapper.java b/src/com/vaadin/ui/DragAndDropWrapper.java
index c6522f15c7..512b70e118 100644
--- a/src/com/vaadin/ui/DragAndDropWrapper.java
+++ b/src/com/vaadin/ui/DragAndDropWrapper.java
@@ -22,11 +22,12 @@ import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.StreamVariable;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper;
+import com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapperPaintable;
import com.vaadin.terminal.gwt.client.ui.dd.HorizontalDropLocation;
import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
@SuppressWarnings("serial")
-@ClientWidget(VDragAndDropWrapper.class)
+@ClientWidget(VDragAndDropWrapperPaintable.class)
public class DragAndDropWrapper extends CustomComponent implements DropTarget,
DragSource {
diff --git a/src/com/vaadin/ui/Embedded.java b/src/com/vaadin/ui/Embedded.java
index dc14cc6ef8..f655b55711 100644
--- a/src/com/vaadin/ui/Embedded.java
+++ b/src/com/vaadin/ui/Embedded.java
@@ -14,7 +14,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.ui.VEmbedded;
+import com.vaadin.terminal.gwt.client.ui.VEmbeddedPaintable;
/**
* Component for embedding external objects.
@@ -25,10 +25,10 @@ import com.vaadin.terminal.gwt.client.ui.VEmbedded;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VEmbedded.class)
+@ClientWidget(VEmbeddedPaintable.class)
public class Embedded extends AbstractComponent {
- private static final String CLICK_EVENT = VEmbedded.CLICK_EVENT_IDENTIFIER;
+ private static final String CLICK_EVENT = VEmbeddedPaintable.CLICK_EVENT_IDENTIFIER;
/**
* General object type.
diff --git a/src/com/vaadin/ui/ExpandLayout.java b/src/com/vaadin/ui/ExpandLayout.java
deleted file mode 100644
index 55ee2ffdcf..0000000000
--- a/src/com/vaadin/ui/ExpandLayout.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.ui;
-
-/**
- * A layout that will give one of it's components as much space as possible,
- * while still showing the other components in the layout. The other components
- * will in effect be given a fixed sized space, while the space given to the
- * expanded component will grow/shrink to fill the rest of the space available -
- * for instance when re-sizing the window.
- *
- * Note that this layout is 100% in both directions by default ({link
- * {@link #setSizeFull()}). Remember to set the units if you want to specify a
- * fixed size. If the layout fails to show up, check that the parent layout is
- * actually giving some space.
- *
- * @deprecated Deprecated in favor of the new OrderedLayout
- */
-@SuppressWarnings("serial")
-@Deprecated
-public class ExpandLayout extends OrderedLayout {
-
- private Component expanded = null;
-
- public ExpandLayout() {
- this(ORIENTATION_VERTICAL);
- }
-
- public ExpandLayout(int orientation) {
- super(orientation);
-
- setSizeFull();
- }
-
- /**
- * @param c
- * Component which container will be maximized
- */
- public void expand(Component c) {
- if (expanded != null) {
- try {
- setExpandRatio(expanded, 0.0f);
- } catch (IllegalArgumentException e) {
- // Ignore error if component has been removed
- }
- }
-
- expanded = c;
- if (expanded != null) {
- setExpandRatio(expanded, 1.0f);
- }
-
- requestRepaint();
- }
-
- @Override
- public void addComponent(Component c, int index) {
- super.addComponent(c, index);
- if (expanded == null) {
- expand(c);
- }
- }
-
- @Override
- public void addComponent(Component c) {
- super.addComponent(c);
- if (expanded == null) {
- expand(c);
- }
- }
-
- @Override
- public void addComponentAsFirst(Component c) {
- super.addComponentAsFirst(c);
- if (expanded == null) {
- expand(c);
- }
- }
-
- @Override
- public void removeComponent(Component c) {
- super.removeComponent(c);
- if (c == expanded) {
- if (getComponentIterator().hasNext()) {
- expand(getComponentIterator().next());
- } else {
- expand(null);
- }
- }
- }
-
- @Override
- public void replaceComponent(Component oldComponent, Component newComponent) {
- super.replaceComponent(oldComponent, newComponent);
- if (oldComponent == expanded) {
- expand(newComponent);
- }
- }
-}
diff --git a/src/com/vaadin/ui/Field.java b/src/com/vaadin/ui/Field.java
index 0cd6cd2d87..6cc11daf08 100644
--- a/src/com/vaadin/ui/Field.java
+++ b/src/com/vaadin/ui/Field.java
@@ -9,30 +9,20 @@ import com.vaadin.data.Property;
import com.vaadin.ui.Component.Focusable;
/**
+ * TODO document
* @author Vaadin Ltd.
*
+ * @param T
+ * the type of values in the field, which might not be the same type
+ * as that of the data source if converters are used
+ *
+ * @author IT Mill Ltd.
*/
-public interface Field extends Component, BufferedValidatable, Property,
+public interface Field<T> extends Component, BufferedValidatable, Property<T>,
Property.ValueChangeNotifier, Property.ValueChangeListener,
Property.Editor, Focusable {
/**
- * Sets the Caption.
- *
- * @param caption
- */
- void setCaption(String caption);
-
- String getDescription();
-
- /**
- * Sets the Description.
- *
- * @param caption
- */
- void setDescription(String caption);
-
- /**
* Is this field required.
*
* Required fields must filled by the user.
@@ -80,7 +70,7 @@ public interface Field extends Component, BufferedValidatable, Property,
* @since 3.0
*/
@SuppressWarnings("serial")
- public class ValueChangeEvent extends Component.Event implements
+ public static class ValueChangeEvent extends Component.Event implements
Property.ValueChangeEvent {
/**
diff --git a/src/com/vaadin/ui/FieldFactory.java b/src/com/vaadin/ui/FieldFactory.java
deleted file mode 100644
index d18918640e..0000000000
--- a/src/com/vaadin/ui/FieldFactory.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.ui;
-
-import com.vaadin.data.Property;
-
-/**
- * Factory for creating new Field-instances based on type, datasource and/or
- * context.
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.1
- * @deprecated FieldFactory was split into two lighter interfaces in 6.0 Use
- * FormFieldFactory or TableFieldFactory or both instead.
- */
-@Deprecated
-public interface FieldFactory extends FormFieldFactory, TableFieldFactory {
-
- /**
- * Creates a field based on type of data.
- *
- * @param type
- * the type of data presented in field.
- * @param uiContext
- * the component where the field is presented.
- * @return Field the field suitable for editing the specified data.
- *
- */
- Field createField(Class<?> type, Component uiContext);
-
- /**
- * Creates a field based on the property datasource.
- *
- * @param property
- * the property datasource.
- * @param uiContext
- * the component where the field is presented.
- * @return Field the field suitable for editing the specified data.
- */
- Field createField(Property property, Component uiContext);
-
-} \ No newline at end of file
diff --git a/src/com/vaadin/ui/Form.java b/src/com/vaadin/ui/Form.java
index c3bb725edf..c79804c7e7 100644
--- a/src/com/vaadin/ui/Form.java
+++ b/src/com/vaadin/ui/Form.java
@@ -17,6 +17,7 @@ import com.vaadin.data.Property;
import com.vaadin.data.Validatable;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
+import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.util.BeanItem;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
@@ -26,7 +27,7 @@ import com.vaadin.terminal.CompositeErrorMessage;
import com.vaadin.terminal.ErrorMessage;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VForm;
+import com.vaadin.terminal.gwt.client.ui.VFormPaintable;
/**
* Form component provides easy way of creating and managing sets fields.
@@ -58,11 +59,13 @@ import com.vaadin.terminal.gwt.client.ui.VForm;
* @version
* @VERSION@
* @since 3.0
+ * @deprecated Use {@link FieldGroup} instead of {@link Form} for more
+ * flexibility.
*/
-@SuppressWarnings("serial")
-@ClientWidget(VForm.class)
-public class Form extends AbstractField implements Item.Editor, Buffered, Item,
- Validatable, Action.Notifier {
+@ClientWidget(VFormPaintable.class)
+@Deprecated
+public class Form extends AbstractField<Object> implements Item.Editor,
+ Buffered, Item, Validatable, Action.Notifier {
private Object propertyValue;
@@ -99,12 +102,12 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
/**
* Mapping from propertyName to corresponding field.
*/
- private final HashMap<Object, Field> fields = new HashMap<Object, Field>();
+ private final HashMap<Object, Field<?>> fields = new HashMap<Object, Field<?>>();
/**
* Form may act as an Item, its own properties are stored here.
*/
- private final HashMap<Object, Property> ownProperties = new HashMap<Object, Property>();
+ private final HashMap<Object, Property<?>> ownProperties = new HashMap<Object, Property<?>>();
/**
* Field factory for this form.
@@ -242,7 +245,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
field.getCaption());
}
break;
- } else if (f instanceof Field && !((Field) f).isValid()) {
+ } else if (f instanceof Field && !((Field<?>) f).isValid()) {
// Something is wrong with the field, but no proper
// error is given. Generate one.
validationError = new Validator.InvalidValueException(
@@ -321,7 +324,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
// Try to commit all
for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) {
try {
- final Field f = (fields.get(i.next()));
+ final Field<?> f = (fields.get(i.next()));
// Commit only non-readonly fields.
if (!f.isReadOnly()) {
f.commit();
@@ -408,7 +411,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
@Override
public boolean isModified() {
for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) {
- final Field f = fields.get(i.next());
+ final Field<?> f = fields.get(i.next());
if (f != null && f.isModified()) {
return true;
}
@@ -422,6 +425,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
* we use the default one from the interface.
*/
@Override
+ @Deprecated
public boolean isReadThrough() {
return readThrough;
}
@@ -431,6 +435,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
* we use the default one from the interface.
*/
@Override
+ @Deprecated
public boolean isWriteThrough() {
return writeThrough;
}
@@ -485,7 +490,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
ownProperties.put(id, property);
// Gets suitable field
- final Field field = fieldFactory.createField(this, id, this);
+ final Field<?> field = fieldFactory.createField(this, id, this);
if (field == null) {
return false;
}
@@ -516,7 +521,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
* @param field
* the field which should be added to the form.
*/
- public void addField(Object propertyId, Field field) {
+ public void addField(Object propertyId, Field<?> field) {
registerField(propertyId, field);
attachField(propertyId, field);
requestRepaint();
@@ -536,7 +541,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
* @param field
* the Field that should be registered
*/
- private void registerField(Object propertyId, Field field) {
+ private void registerField(Object propertyId, Field<?> field) {
if (propertyId == null || field == null) {
return;
}
@@ -599,13 +604,13 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
*
* @see com.vaadin.data.Item#getItemProperty(Object)
*/
- public Property getItemProperty(Object id) {
- final Field field = fields.get(id);
+ public Property<?> getItemProperty(Object id) {
+ final Field<?> field = fields.get(id);
if (field == null) {
// field does not exist or it is not (yet) created for this property
return ownProperties.get(id);
}
- final Property property = field.getPropertyDataSource();
+ final Property<?> property = field.getPropertyDataSource();
if (property != null) {
return property;
@@ -620,7 +625,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
* @param propertyId
* the id of the property.
*/
- public Field getField(Object propertyId) {
+ public Field<?> getField(Object propertyId) {
return fields.get(propertyId);
}
@@ -637,7 +642,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
public boolean removeItemProperty(Object id) {
ownProperties.remove(id);
- final Field field = fields.get(id);
+ final Field<?> field = fields.get(id);
if (field != null) {
propertyIds.remove(id);
@@ -750,9 +755,9 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
// Adds all the properties to this form
for (final Iterator<?> i = propertyIds.iterator(); i.hasNext();) {
final Object id = i.next();
- final Property property = itemDatasource.getItemProperty(id);
+ final Property<?> property = itemDatasource.getItemProperty(id);
if (id != null && property != null) {
- final Field f = fieldFactory.createField(itemDatasource, id,
+ final Field<?> f = fieldFactory.createField(itemDatasource, id,
this);
if (f != null) {
bindPropertyToField(id, property, f);
@@ -828,7 +833,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
if (layout != null) {
final Object[] properties = propertyIds.toArray();
for (int i = 0; i < properties.length; i++) {
- Field f = getField(properties[i]);
+ Field<?> f = getField(properties[i]);
detachField(f);
if (newLayout instanceof CustomLayout) {
((CustomLayout) newLayout).addComponent(f,
@@ -875,7 +880,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
}
// Gets the old field
- final Field oldField = fields.get(propertyId);
+ final Field<?> oldField = fields.get(propertyId);
if (oldField == null) {
throw new IllegalArgumentException("Field with given propertyid '"
+ propertyId.toString() + "' can not be found.");
@@ -952,7 +957,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
}
// Sets the property data source
- final Property property = oldField.getPropertyDataSource();
+ final Property<?> property = oldField.getPropertyDataSource();
oldField.setPropertyDataSource(null);
newField.setPropertyDataSource(property);
@@ -994,21 +999,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
}
/**
- * Tests the current value of the object against all registered validators
- *
- * @see com.vaadin.data.Validatable#isValid()
- */
- @Override
- public boolean isValid() {
- boolean valid = true;
- for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) {
- valid &= (fields.get(i.next())).isValid();
- }
- return valid && super.isValid();
- }
-
- /**
- * Checks the validity of the validatable.
+ * Checks the validity of the Form and all of its fields.
*
* @see com.vaadin.data.Validatable#validate()
*/
@@ -1055,23 +1046,6 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
}
/**
- * Sets the field factory of Form.
- *
- * <code>FieldFactory</code> is used to create fields for form properties.
- * By default the form uses BaseFieldFactory to create Field instances.
- *
- * @param fieldFactory
- * the New factory used to create the fields.
- * @see Field
- * @see FormFieldFactory
- * @deprecated use {@link #setFormFieldFactory(FormFieldFactory)} instead
- */
- @Deprecated
- public void setFieldFactory(FieldFactory fieldFactory) {
- this.fieldFactory = fieldFactory;
- }
-
- /**
* Sets the field factory used by this Form to genarate Fields for
* properties.
*
@@ -1097,23 +1071,6 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
}
/**
- * Get the field factory of the form.
- *
- * @return the FieldFactory Factory used to create the fields.
- * @deprecated Use {@link #getFormFieldFactory()} instead. Set the
- * FormFieldFactory using
- * {@link #setFormFieldFactory(FormFieldFactory)}.
- */
- @Deprecated
- public FieldFactory getFieldFactory() {
- if (fieldFactory instanceof FieldFactory) {
- return (FieldFactory) fieldFactory;
-
- }
- return null;
- }
-
- /**
* Gets the field type.
*
* @see com.vaadin.ui.AbstractField#getType()
@@ -1155,11 +1112,11 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
*
* @return the Field.
*/
- private Field getFirstFocusableField() {
+ private Field<?> getFirstFocusableField() {
if (getItemPropertyIds() != null) {
for (Object id : getItemPropertyIds()) {
if (id != null) {
- Field field = getField(id);
+ Field<?> field = getField(id);
if (field.isEnabled() && !field.isReadOnly()) {
return field;
}
@@ -1248,7 +1205,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
*/
@Override
public void focus() {
- final Field f = getFirstFocusableField();
+ final Field<?> f = getFirstFocusableField();
if (f != null) {
f.focus();
}
@@ -1274,8 +1231,8 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
@Override
public void setImmediate(boolean immediate) {
super.setImmediate(immediate);
- for (Iterator<Field> i = fields.values().iterator(); i.hasNext();) {
- Field f = i.next();
+ for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) {
+ Field<?> f = i.next();
if (f instanceof AbstractComponent) {
((AbstractComponent) f).setImmediate(immediate);
}
@@ -1286,10 +1243,10 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
@Override
protected boolean isEmpty() {
- for (Iterator<Field> i = fields.values().iterator(); i.hasNext();) {
- Field f = i.next();
+ for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) {
+ Field<?> f = i.next();
if (f instanceof AbstractField) {
- if (!((AbstractField) f).isEmpty()) {
+ if (!((AbstractField<?>) f).isEmpty()) {
return false;
}
}
diff --git a/src/com/vaadin/ui/FormFieldFactory.java b/src/com/vaadin/ui/FormFieldFactory.java
index 52ecfcd8c2..1efa05c5f5 100644
--- a/src/com/vaadin/ui/FormFieldFactory.java
+++ b/src/com/vaadin/ui/FormFieldFactory.java
@@ -37,5 +37,5 @@ public interface FormFieldFactory extends Serializable {
* creating it.
* @return Field the field suitable for editing the specified data.
*/
- Field createField(Item item, Object propertyId, Component uiContext);
+ Field<?> createField(Item item, Object propertyId, Component uiContext);
}
diff --git a/src/com/vaadin/ui/FormLayout.java b/src/com/vaadin/ui/FormLayout.java
index f61f5d544e..c5c211924e 100644
--- a/src/com/vaadin/ui/FormLayout.java
+++ b/src/com/vaadin/ui/FormLayout.java
@@ -4,7 +4,7 @@
package com.vaadin.ui;
-import com.vaadin.terminal.gwt.client.ui.VFormLayout;
+import com.vaadin.terminal.gwt.client.ui.VFormLayoutPaintable;
/**
* FormLayout is used by {@link Form} to layout fields. It may also be used
@@ -21,14 +21,14 @@ import com.vaadin.terminal.gwt.client.ui.VFormLayout;
* bottom are by default on.
*
*/
-@SuppressWarnings({ "deprecation", "serial" })
-@ClientWidget(VFormLayout.class)
-public class FormLayout extends OrderedLayout {
+@ClientWidget(VFormLayoutPaintable.class)
+public class FormLayout extends AbstractOrderedLayout {
public FormLayout() {
super();
setSpacing(true);
setMargin(true, false, true, false);
+ setWidth(100, UNITS_PERCENTAGE);
}
}
diff --git a/src/com/vaadin/ui/GridLayout.java b/src/com/vaadin/ui/GridLayout.java
index 24a57d462b..4588328345 100644
--- a/src/com/vaadin/ui/GridLayout.java
+++ b/src/com/vaadin/ui/GridLayout.java
@@ -18,7 +18,7 @@ import com.vaadin.event.LayoutEvents.LayoutClickNotifier;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.ui.VGridLayout;
+import com.vaadin.terminal.gwt.client.ui.VGridLayoutPaintable;
/**
* <p>
@@ -41,7 +41,7 @@ import com.vaadin.terminal.gwt.client.ui.VGridLayout;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VGridLayout.class)
+@ClientWidget(VGridLayoutPaintable.class)
public class GridLayout extends AbstractLayout implements
Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier {
diff --git a/src/com/vaadin/ui/HorizontalLayout.java b/src/com/vaadin/ui/HorizontalLayout.java
index ed1cad8184..ba685ec410 100644
--- a/src/com/vaadin/ui/HorizontalLayout.java
+++ b/src/com/vaadin/ui/HorizontalLayout.java
@@ -3,7 +3,7 @@
*/
package com.vaadin.ui;
-import com.vaadin.terminal.gwt.client.ui.VHorizontalLayout;
+import com.vaadin.terminal.gwt.client.ui.VHorizontalLayoutPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -18,7 +18,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* @since 5.3
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VHorizontalLayout.class, loadStyle = LoadStyle.EAGER)
+@ClientWidget(value = VHorizontalLayoutPaintable.class, loadStyle = LoadStyle.EAGER)
public class HorizontalLayout extends AbstractOrderedLayout {
public HorizontalLayout() {
diff --git a/src/com/vaadin/ui/HorizontalSplitPanel.java b/src/com/vaadin/ui/HorizontalSplitPanel.java
index d9368635df..d4a1e7cc0e 100644
--- a/src/com/vaadin/ui/HorizontalSplitPanel.java
+++ b/src/com/vaadin/ui/HorizontalSplitPanel.java
@@ -3,7 +3,7 @@
*/
package com.vaadin.ui;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal;
+import com.vaadin.terminal.gwt.client.ui.VHorizontalSplitPanelPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -29,7 +29,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* @VERSION@
* @since 6.5
*/
-@ClientWidget(value = VSplitPanelHorizontal.class, loadStyle = LoadStyle.EAGER)
+@ClientWidget(value = VHorizontalSplitPanelPaintable.class, loadStyle = LoadStyle.EAGER)
public class HorizontalSplitPanel extends AbstractSplitPanel {
public HorizontalSplitPanel() {
super();
diff --git a/src/com/vaadin/ui/InlineDateField.java b/src/com/vaadin/ui/InlineDateField.java
index 50e16d803b..b4160604ff 100644
--- a/src/com/vaadin/ui/InlineDateField.java
+++ b/src/com/vaadin/ui/InlineDateField.java
@@ -7,7 +7,7 @@ package com.vaadin.ui;
import java.util.Date;
import com.vaadin.data.Property;
-import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar;
+import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendarPaintable;
/**
* <p>
@@ -22,7 +22,7 @@ import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar;
* @VERSION@
* @since 5.0
*/
-@ClientWidget(VDateFieldCalendar.class)
+@ClientWidget(VDateFieldCalendarPaintable.class)
public class InlineDateField extends DateField {
public InlineDateField() {
diff --git a/src/com/vaadin/ui/Label.java b/src/com/vaadin/ui/Label.java
index 2dadf4f5c5..576bbd967f 100644
--- a/src/com/vaadin/ui/Label.java
+++ b/src/com/vaadin/ui/Label.java
@@ -10,14 +10,13 @@ import com.vaadin.data.Property;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VLabel;
+import com.vaadin.terminal.gwt.client.ui.label.VLabelPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
* Label component for showing non-editable short texts.
*
- * The label content can be set to the modes specified by the final members
- * CONTENT_*
+ * The label content can be set to the modes specified by {@link ContentMode}
*
* <p>
* The contents of the label may contain simple formatting:
@@ -39,67 +38,166 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VLabel.class, loadStyle = LoadStyle.EAGER)
+@ClientWidget(value = VLabelPaintable.class, loadStyle = LoadStyle.EAGER)
+// TODO generics for interface Property
public class Label extends AbstractComponent implements Property,
Property.Viewer, Property.ValueChangeListener,
Property.ValueChangeNotifier, Comparable<Object> {
/**
- * Content mode, where the label contains only plain text. The getValue()
- * result is coded to XML when painting.
+ * Content modes defining how the client should interpret a Label's value.
+ *
+ * @sine 7.0
*/
- public static final int CONTENT_TEXT = 0;
+ public enum ContentMode {
+ /**
+ * Content mode, where the label contains only plain text. The
+ * getValue() result is coded to XML when painting.
+ */
+ TEXT(null) {
+ @Override
+ public void paintText(String text, PaintTarget target)
+ throws PaintException {
+ target.addText(text);
+ }
+ },
+
+ /**
+ * Content mode, where the label contains preformatted text.
+ */
+ PREFORMATTED("pre") {
+ @Override
+ public void paintText(String text, PaintTarget target)
+ throws PaintException {
+ target.startTag("pre");
+ target.addText(text);
+ target.endTag("pre");
+ }
+ },
+
+ /**
+ * Content mode, where the label contains XHTML. Contents is then
+ * enclosed in DIV elements having namespace of
+ * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".
+ */
+ XHTML("xhtml") {
+ @Override
+ public void paintText(String text, PaintTarget target)
+ throws PaintException {
+ target.startTag("data");
+ target.addXMLSection("div", text,
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
+ target.endTag("data");
+ }
+ },
+
+ /**
+ * Content mode, where the label contains well-formed or well-balanced
+ * XML. Each of the root elements must have their default namespace
+ * specified.
+ */
+ XML("xml") {
+ @Override
+ public void paintText(String text, PaintTarget target)
+ throws PaintException {
+ target.addXMLSection("data", text, null);
+ }
+ },
+
+ /**
+ * Content mode, where the label contains RAW output. Output is not
+ * required to comply to with XML. In Web Adapter output is inserted
+ * inside the resulting HTML document as-is. This is useful for some
+ * specific purposes where possibly broken HTML content needs to be
+ * shown, but in most cases XHTML mode should be preferred.
+ */
+ RAW("raw") {
+ @Override
+ public void paintText(String text, PaintTarget target)
+ throws PaintException {
+ target.startTag("data");
+ target.addAttribute("escape", false);
+ target.addText(text);
+ target.endTag("data");
+ }
+ };
+
+ private final String uidlName;
+
+ /**
+ * The default content mode is text
+ */
+ public static ContentMode DEFAULT = TEXT;
+
+ private ContentMode(String uidlName) {
+ this.uidlName = uidlName;
+ }
+
+ /**
+ * Gets the name representing this content mode in UIDL messages
+ *
+ * @return the UIDL name of this content mode
+ */
+ public String getUidlName() {
+ return uidlName;
+ }
+
+ /**
+ * Adds the text value to a {@link PaintTarget} according to this
+ * content mode
+ *
+ * @param text
+ * the text to add
+ * @param target
+ * the paint target to add the value to
+ * @throws PaintException
+ * if the paint operation failed
+ */
+ public abstract void paintText(String text, PaintTarget target)
+ throws PaintException;
+ }
/**
- * Content mode, where the label contains preformatted text.
+ * @deprecated From 7.0, use {@link ContentMode#TEXT} instead
*/
- public static final int CONTENT_PREFORMATTED = 1;
+ @Deprecated
+ public static final ContentMode CONTENT_TEXT = ContentMode.TEXT;
/**
- * Formatted content mode, where the contents is XML restricted to the UIDL
- * 1.0 formatting markups.
- *
- * @deprecated Use CONTENT_XML instead.
+ * @deprecated From 7.0, use {@link ContentMode#PREFORMATTED} instead
*/
@Deprecated
- public static final int CONTENT_UIDL = 2;
+ public static final ContentMode CONTENT_PREFORMATTED = ContentMode.PREFORMATTED;
/**
- * Content mode, where the label contains XHTML. Contents is then enclosed
- * in DIV elements having namespace of
- * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".
+ * @deprecated From 7.0, use {@link ContentMode#XHTML} instead
*/
- public static final int CONTENT_XHTML = 3;
+ @Deprecated
+ public static final ContentMode CONTENT_XHTML = ContentMode.XHTML;
/**
- * Content mode, where the label contains well-formed or well-balanced XML.
- * Each of the root elements must have their default namespace specified.
+ * @deprecated From 7.0, use {@link ContentMode#XML} instead
*/
- public static final int CONTENT_XML = 4;
+ @Deprecated
+ public static final ContentMode CONTENT_XML = ContentMode.XML;
/**
- * Content mode, where the label contains RAW output. Output is not required
- * to comply to with XML. In Web Adapter output is inserted inside the
- * resulting HTML document as-is. This is useful for some specific purposes
- * where possibly broken HTML content needs to be shown, but in most cases
- * XHTML mode should be preferred.
+ * @deprecated From 7.0, use {@link ContentMode#RAW} instead
*/
- public static final int CONTENT_RAW = 5;
+ @Deprecated
+ public static final ContentMode CONTENT_RAW = ContentMode.RAW;
/**
- * The default content mode is plain text.
+ * @deprecated From 7.0, use {@link ContentMode#DEFAULT} instead
*/
- public static final int CONTENT_DEFAULT = CONTENT_TEXT;
-
- /** Array of content mode names that are rendered in UIDL as mode attribute. */
- private static final String[] CONTENT_MODE_NAME = { "text", "pre", "uidl",
- "xhtml", "xml", "raw" };
+ @Deprecated
+ public static final ContentMode CONTENT_DEFAULT = ContentMode.DEFAULT;
private static final String DATASOURCE_MUST_BE_SET = "Datasource must be set";
private Property dataSource;
- private int contentMode = CONTENT_DEFAULT;
+ private ContentMode contentMode = ContentMode.DEFAULT;
/**
* Creates an empty Label.
@@ -114,7 +212,7 @@ public class Label extends AbstractComponent implements Property,
* @param content
*/
public Label(String content) {
- this(content, CONTENT_DEFAULT);
+ this(content, ContentMode.DEFAULT);
}
/**
@@ -124,7 +222,7 @@ public class Label extends AbstractComponent implements Property,
* @param contentSource
*/
public Label(Property contentSource) {
- this(contentSource, CONTENT_DEFAULT);
+ this(contentSource, ContentMode.DEFAULT);
}
/**
@@ -133,7 +231,7 @@ public class Label extends AbstractComponent implements Property,
* @param content
* @param contentMode
*/
- public Label(String content, int contentMode) {
+ public Label(String content, ContentMode contentMode) {
this(new ObjectProperty<String>(content, String.class), contentMode);
}
@@ -144,43 +242,15 @@ public class Label extends AbstractComponent implements Property,
* @param contentSource
* @param contentMode
*/
- public Label(Property contentSource, int contentMode) {
+ public Label(Property contentSource, ContentMode contentMode) {
setPropertyDataSource(contentSource);
- if (contentMode != CONTENT_DEFAULT) {
+ if (contentMode != ContentMode.DEFAULT) {
setContentMode(contentMode);
}
setWidth(100, UNITS_PERCENTAGE);
}
/**
- * Set the component to read-only. Readonly is not used in label.
- *
- * @param readOnly
- * True to enable read-only mode, False to disable it.
- */
- @Override
- public void setReadOnly(boolean readOnly) {
- if (dataSource == null) {
- throw new IllegalStateException(DATASOURCE_MUST_BE_SET);
- }
- dataSource.setReadOnly(readOnly);
- }
-
- /**
- * Is the component read-only ? Readonly is not used in label - this returns
- * allways false.
- *
- * @return <code>true</code> if the component is in read only mode.
- */
- @Override
- public boolean isReadOnly() {
- if (dataSource == null) {
- throw new IllegalStateException(DATASOURCE_MUST_BE_SET);
- }
- return dataSource.isReadOnly();
- }
-
- /**
* Paints the content of this component.
*
* @param target
@@ -190,30 +260,11 @@ public class Label extends AbstractComponent implements Property,
*/
@Override
public void paintContent(PaintTarget target) throws PaintException {
- if (contentMode != CONTENT_TEXT) {
- target.addAttribute("mode", CONTENT_MODE_NAME[contentMode]);
- }
- if (contentMode == CONTENT_TEXT) {
- target.addText(toString());
- } else if (contentMode == CONTENT_UIDL) {
- target.addUIDL(toString());
- } else if (contentMode == CONTENT_XHTML) {
- target.startTag("data");
- target.addXMLSection("div", toString(),
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
- target.endTag("data");
- } else if (contentMode == CONTENT_PREFORMATTED) {
- target.startTag("pre");
- target.addText(toString());
- target.endTag("pre");
- } else if (contentMode == CONTENT_XML) {
- target.addXMLSection("data", toString(), null);
- } else if (contentMode == CONTENT_RAW) {
- target.startTag("data");
- target.addAttribute("escape", false);
- target.addText(toString());
- target.endTag("data");
+ String uidlName = contentMode.getUidlName();
+ if (uidlName != null) {
+ target.addAttribute("mode", uidlName);
}
+ contentMode.paintText(getStringValue(), target);
}
@@ -246,13 +297,33 @@ public class Label extends AbstractComponent implements Property,
/**
* @see java.lang.Object#toString()
+ * @deprecated use the data source value or {@link #getStringValue()}
+ * instead
*/
+ @Deprecated
@Override
public String toString() {
+ throw new UnsupportedOperationException(
+ "Use Property.getValue() instead of Label.toString()");
+ }
+
+ /**
+ * Returns the value of the <code>Property</code> in human readable textual
+ * format.
+ *
+ * This method exists to help migration from previous Vaadin versions by
+ * providing a simple replacement for {@link #toString()}. However, it is
+ * normally better to use the value of the label directly.
+ *
+ * @return String representation of the value stored in the Property
+ * @since 7.0
+ */
+ public String getStringValue() {
if (dataSource == null) {
throw new IllegalStateException(DATASOURCE_MUST_BE_SET);
}
- return dataSource.toString();
+ Object value = dataSource.getValue();
+ return (null != value) ? value.toString() : null;
}
/**
@@ -307,67 +378,27 @@ public class Label extends AbstractComponent implements Property,
/**
* Gets the content mode of the Label.
*
- * <p>
- * Possible content modes include:
- * <ul>
- * <li><b>CONTENT_TEXT</b> Content mode, where the label contains only plain
- * text. The getValue() result is coded to XML when painting.</li>
- * <li><b>CONTENT_PREFORMATTED</b> Content mode, where the label contains
- * preformatted text.</li>
- * <li><b>CONTENT_UIDL</b> Formatted content mode, where the contents is XML
- * restricted to the UIDL 1.0 formatting markups.</li>
- * <li><b>CONTENT_XHTML</b> Content mode, where the label contains XHTML.
- * Contents is then enclosed in DIV elements having namespace of
- * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".</li>
- * <li><b>CONTENT_XML</b> Content mode, where the label contains well-formed
- * or well-balanced XML. Each of the root elements must have their default
- * namespace specified.</li>
- * <li><b>CONTENT_RAW</b> Content mode, where the label contains RAW output.
- * Output is not required to comply to with XML. In Web Adapter output is
- * inserted inside the resulting HTML document as-is. This is useful for
- * some specific purposes where possibly broken HTML content needs to be
- * shown, but in most cases XHTML mode should be preferred.</li>
- * </ul>
- * </p>
- *
* @return the Content mode of the label.
+ *
+ * @see ContentMode
*/
- public int getContentMode() {
+ public ContentMode getContentMode() {
return contentMode;
}
/**
* Sets the content mode of the Label.
*
- * <p>
- * Possible content modes include:
- * <ul>
- * <li><b>CONTENT_TEXT</b> Content mode, where the label contains only plain
- * text. The getValue() result is coded to XML when painting.</li>
- * <li><b>CONTENT_PREFORMATTED</b> Content mode, where the label contains
- * preformatted text.</li>
- * <li><b>CONTENT_UIDL</b> Formatted content mode, where the contents is XML
- * restricted to the UIDL 1.0 formatting markups.</li>
- * <li><b>CONTENT_XHTML</b> Content mode, where the label contains XHTML.
- * Contents is then enclosed in DIV elements having namespace of
- * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".</li>
- * <li><b>CONTENT_XML</b> Content mode, where the label contains well-formed
- * or well-balanced XML. Each of the root elements must have their default
- * namespace specified.</li>
- * <li><b>CONTENT_RAW</b> Content mode, where the label contains RAW output.
- * Output is not required to comply to with XML. In Web Adapter output is
- * inserted inside the resulting HTML document as-is. This is useful for
- * some specific purposes where possibly broken HTML content needs to be
- * shown, but in most cases XHTML mode should be preferred.</li>
- * </ul>
- * </p>
- *
* @param contentMode
* the New content mode of the label.
+ *
+ * @see ContentMode
*/
- public void setContentMode(int contentMode) {
- if (contentMode != this.contentMode && contentMode >= CONTENT_TEXT
- && contentMode <= CONTENT_RAW) {
+ public void setContentMode(ContentMode contentMode) {
+ if (contentMode == null) {
+ throw new IllegalArgumentException("Content mode can not be null");
+ }
+ if (contentMode != this.contentMode) {
this.contentMode = contentMode;
requestRepaint();
}
@@ -397,7 +428,7 @@ public class Label extends AbstractComponent implements Property,
* @VERSION@
* @since 3.0
*/
- public class ValueChangeEvent extends Component.Event implements
+ public static class ValueChangeEvent extends Component.Event implements
Property.ValueChangeEvent {
/**
@@ -487,19 +518,19 @@ public class Label extends AbstractComponent implements Property,
String thisValue;
String otherValue;
- if (contentMode == CONTENT_XML || contentMode == CONTENT_UIDL
- || contentMode == CONTENT_XHTML) {
- thisValue = stripTags(toString());
+ if (contentMode == ContentMode.XML || contentMode == ContentMode.XHTML) {
+ thisValue = stripTags(getStringValue());
} else {
- thisValue = toString();
+ thisValue = getStringValue();
}
if (other instanceof Label
- && (((Label) other).getContentMode() == CONTENT_XML
- || ((Label) other).getContentMode() == CONTENT_UIDL || ((Label) other)
- .getContentMode() == CONTENT_XHTML)) {
- otherValue = stripTags(other.toString());
+ && (((Label) other).getContentMode() == ContentMode.XML || ((Label) other)
+ .getContentMode() == ContentMode.XHTML)) {
+ otherValue = stripTags(((Label) other).getStringValue());
} else {
+ // TODO not a good idea - and might assume that Field.toString()
+ // returns a string representation of the value
otherValue = other.toString();
}
diff --git a/src/com/vaadin/ui/Link.java b/src/com/vaadin/ui/Link.java
index ebea47118a..0b11151be7 100644
--- a/src/com/vaadin/ui/Link.java
+++ b/src/com/vaadin/ui/Link.java
@@ -7,7 +7,7 @@ package com.vaadin.ui;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
-import com.vaadin.terminal.gwt.client.ui.VLink;
+import com.vaadin.terminal.gwt.client.ui.VLinkPaintable;
/**
* Link is used to create external or internal URL links.
@@ -18,17 +18,17 @@ import com.vaadin.terminal.gwt.client.ui.VLink;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VLink.class)
+@ClientWidget(VLinkPaintable.class)
public class Link extends AbstractComponent {
/* Target window border type constant: No window border */
- public static final int TARGET_BORDER_NONE = Window.BORDER_NONE;
+ public static final int TARGET_BORDER_NONE = Root.BORDER_NONE;
/* Target window border type constant: Minimal window border */
- public static final int TARGET_BORDER_MINIMAL = Window.BORDER_MINIMAL;
+ public static final int TARGET_BORDER_MINIMAL = Root.BORDER_MINIMAL;
/* Target window border type constant: Default window border */
- public static final int TARGET_BORDER_DEFAULT = Window.BORDER_DEFAULT;
+ public static final int TARGET_BORDER_DEFAULT = Root.BORDER_DEFAULT;
private Resource resource = null;
diff --git a/src/com/vaadin/ui/ListSelect.java b/src/com/vaadin/ui/ListSelect.java
index 5c879f00f5..cf0e6773f2 100644
--- a/src/com/vaadin/ui/ListSelect.java
+++ b/src/com/vaadin/ui/ListSelect.java
@@ -9,14 +9,14 @@ import java.util.Collection;
import com.vaadin.data.Container;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VListSelect;
+import com.vaadin.terminal.gwt.client.ui.VListSelectPaintable;
/**
* This is a simple list select without, for instance, support for new items,
* lazyloading, and other advanced features.
*/
@SuppressWarnings("serial")
-@ClientWidget(VListSelect.class)
+@ClientWidget(VListSelectPaintable.class)
public class ListSelect extends AbstractSelect {
private int columns = 0;
diff --git a/src/com/vaadin/ui/LoginForm.java b/src/com/vaadin/ui/LoginForm.java
index 80e002435e..7eaeb824c9 100644
--- a/src/com/vaadin/ui/LoginForm.java
+++ b/src/com/vaadin/ui/LoginForm.java
@@ -4,10 +4,10 @@
package com.vaadin.ui;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
-import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -15,8 +15,9 @@ import java.util.Map;
import com.vaadin.Application;
import com.vaadin.terminal.ApplicationResource;
import com.vaadin.terminal.DownloadStream;
-import com.vaadin.terminal.ParameterHandler;
-import com.vaadin.terminal.URIHandler;
+import com.vaadin.terminal.RequestHandler;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedResponse;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
/**
@@ -73,11 +74,20 @@ public class LoginForm extends CustomComponent {
}
};
- private ParameterHandler paramHandler = new ParameterHandler() {
-
- public void handleParameters(Map<String, String[]> parameters) {
- if (parameters.containsKey("username")) {
- getWindow().addURIHandler(uriHandler);
+ private final RequestHandler requestHandler = new RequestHandler() {
+ public boolean handleRequest(Application application,
+ WrappedRequest request, WrappedResponse response)
+ throws IOException {
+ String requestPathInfo = request.getRequestPathInfo();
+ if ("/loginHandler".equals(requestPathInfo)) {
+ response.setCacheTime(-1);
+ response.setContentType("text/html; charset=utf-8");
+ response.getWriter()
+ .write("<html><body>Login form handled."
+ + "<script type='text/javascript'>top.vaadin.forceSync();"
+ + "</script></body></html>");
+
+ Map<String, String[]> parameters = request.getParameterMap();
HashMap<String, String> params = new HashMap<String, String>();
// expecting single params
@@ -89,33 +99,12 @@ public class LoginForm extends CustomComponent {
}
LoginEvent event = new LoginEvent(params);
fireEvent(event);
+ return true;
}
+ return false;
}
};
- private URIHandler uriHandler = new URIHandler() {
- private final String responce = "<html><body>Login form handeled."
- + "<script type='text/javascript'>top.vaadin.forceSync();"
- + "</script></body></html>";
-
- public DownloadStream handleURI(URL context, String relativeUri) {
- if (relativeUri != null && relativeUri.contains("loginHandler")) {
- if (window != null) {
- window.removeURIHandler(this);
- }
- DownloadStream downloadStream = new DownloadStream(
- new ByteArrayInputStream(responce.getBytes()),
- "text/html", "loginSuccesfull");
- downloadStream.setCacheTime(-1);
- return downloadStream;
- } else {
- return null;
- }
- }
- };
-
- private Window window;
-
public LoginForm() {
iframe.setType(Embedded.TYPE_BROWSER);
iframe.setSizeFull();
@@ -132,8 +121,7 @@ public class LoginForm extends CustomComponent {
* @return byte array containing login page html
*/
protected byte[] getLoginHTML() {
- String appUri = getApplication().getURL().toString()
- + getWindow().getName() + "/";
+ String appUri = getApplication().getURL().toString();
try {
return ("<!DOCTYPE html PUBLIC \"-//W3C//DTD "
@@ -188,21 +176,15 @@ public class LoginForm extends CustomComponent {
public void attach() {
super.attach();
getApplication().addResource(loginPage);
- getWindow().addParameterHandler(paramHandler);
+ getApplication().addRequestHandler(requestHandler);
iframe.setSource(loginPage);
}
@Override
public void detach() {
getApplication().removeResource(loginPage);
- getWindow().removeParameterHandler(paramHandler);
- // store window temporary to properly remove uri handler once
- // response is handled. (May happen if login handler removes login
- // form
- window = getWindow();
- if (window.getParent() != null) {
- window = window.getParent();
- }
+ getApplication().removeRequestHandler(requestHandler);
+
super.detach();
}
@@ -281,7 +263,7 @@ public class LoginForm extends CustomComponent {
}
@Override
- public void setWidth(float width, int unit) {
+ public void setWidth(float width, Unit unit) {
super.setWidth(width, unit);
if (iframe != null) {
if (width < 0) {
@@ -293,7 +275,7 @@ public class LoginForm extends CustomComponent {
}
@Override
- public void setHeight(float height, int unit) {
+ public void setHeight(float height, Unit unit) {
super.setHeight(height, unit);
if (iframe != null) {
if (height < 0) {
diff --git a/src/com/vaadin/ui/MenuBar.java b/src/com/vaadin/ui/MenuBar.java
index 3469f77ebb..54a094a4e7 100644
--- a/src/com/vaadin/ui/MenuBar.java
+++ b/src/com/vaadin/ui/MenuBar.java
@@ -14,6 +14,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.ui.VMenuBar;
+import com.vaadin.terminal.gwt.client.ui.VMenuBarPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -24,7 +25,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* </p>
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VMenuBar.class, loadStyle = LoadStyle.LAZY)
+@ClientWidget(value = VMenuBarPaintable.class, loadStyle = LoadStyle.LAZY)
public class MenuBar extends AbstractComponent {
// Items of the top-level menu
@@ -33,20 +34,6 @@ public class MenuBar extends AbstractComponent {
// Number of items in this menu
private int numberOfItems = 0;
- /**
- * @deprecated
- * @see #setCollapse(boolean)
- */
- @Deprecated
- private boolean collapseItems;
-
- /**
- * @deprecated
- * @see #setSubmenuIcon(Resource)
- */
- @Deprecated
- private Resource submenuIcon;
-
private MenuItem moreItem;
private boolean openRootOnHover;
@@ -68,10 +55,6 @@ public class MenuBar extends AbstractComponent {
target.startTag("options");
- if (submenuIcon != null) {
- target.addAttribute("submenuIcon", submenuIcon);
- }
-
if (getWidth() > -1) {
target.startTag("moreItem");
target.addAttribute("text", moreItem.getText());
@@ -193,7 +176,6 @@ public class MenuBar extends AbstractComponent {
*/
public MenuBar() {
menuItems = new ArrayList<MenuItem>();
- setCollapse(true);
setMoreMenuItem(null);
}
@@ -311,54 +293,6 @@ public class MenuBar extends AbstractComponent {
}
/**
- * Set the icon to be used if a sub-menu has children. Defaults to null;
- *
- * @param icon
- * @deprecated (since 6.2, will be removed in 7.0) Icon is set in theme, no
- * need to worry about the visual representation here.
- */
- @Deprecated
- public void setSubmenuIcon(Resource icon) {
- submenuIcon = icon;
- requestRepaint();
- }
-
- /**
- * @deprecated
- * @see #setSubmenuIcon(Resource)
- */
- @Deprecated
- public Resource getSubmenuIcon() {
- return submenuIcon;
- }
-
- /**
- * Enable or disable collapsing top-level items. Top-level items will
- * collapse together if there is not enough room for them. Items that don't
- * fit will be placed under the "More" menu item.
- *
- * Collapsing is enabled by default.
- *
- * @param collapse
- * @deprecated (since 6.2, will be removed in 7.0) Collapsing is always
- * enabled if the MenuBar has a specified width.
- */
- @Deprecated
- public void setCollapse(boolean collapse) {
- collapseItems = collapse;
- requestRepaint();
- }
-
- /**
- * @see #setCollapse(boolean)
- * @deprecated
- */
- @Deprecated
- public boolean getCollapse() {
- return collapseItems;
- }
-
- /**
* Set the item that is used when collapsing the top level menu. All
* "overflowing" items will be added below this. The item command will be
* ignored. If set to null, the default item with a downwards arrow is used.
diff --git a/src/com/vaadin/ui/NativeButton.java b/src/com/vaadin/ui/NativeButton.java
index 369b40b93a..b7b7fcb38c 100644
--- a/src/com/vaadin/ui/NativeButton.java
+++ b/src/com/vaadin/ui/NativeButton.java
@@ -3,11 +3,10 @@
*/
package com.vaadin.ui;
-import com.vaadin.data.Property;
-import com.vaadin.terminal.gwt.client.ui.VNativeButton;
+import com.vaadin.terminal.gwt.client.ui.VNativeButtonPaintable;
@SuppressWarnings("serial")
-@ClientWidget(VNativeButton.class)
+@ClientWidget(VNativeButtonPaintable.class)
public class NativeButton extends Button {
public NativeButton() {
@@ -22,34 +21,4 @@ public class NativeButton extends Button {
super(caption, listener);
}
- public NativeButton(String caption, Object target, String methodName) {
- super(caption, target, methodName);
- }
-
- /**
- * Creates a new switch button with initial value.
- *
- * @param state
- * the Initial state of the switch-button.
- * @param initialState
- * @deprecated use the {@link CheckBox} component instead
- */
- @Deprecated
- public NativeButton(String caption, boolean initialState) {
- super(caption, initialState);
- }
-
- /**
- * Creates a new switch button that is connected to a boolean property.
- *
- * @param state
- * the Initial state of the switch-button.
- * @param dataSource
- * @deprecated use the {@link CheckBox} component instead
- */
- @Deprecated
- public NativeButton(String caption, Property dataSource) {
- super(caption, dataSource);
- }
-
-} \ No newline at end of file
+}
diff --git a/src/com/vaadin/ui/NativeSelect.java b/src/com/vaadin/ui/NativeSelect.java
index e701d212b4..b0070426ad 100644
--- a/src/com/vaadin/ui/NativeSelect.java
+++ b/src/com/vaadin/ui/NativeSelect.java
@@ -9,7 +9,7 @@ import java.util.Collection;
import com.vaadin.data.Container;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VNativeSelect;
+import com.vaadin.terminal.gwt.client.ui.VNativeSelectPaintable;
/**
* This is a simple drop-down select without, for instance, support for
@@ -18,7 +18,7 @@ import com.vaadin.terminal.gwt.client.ui.VNativeSelect;
* better choice.
*/
@SuppressWarnings("serial")
-@ClientWidget(VNativeSelect.class)
+@ClientWidget(VNativeSelectPaintable.class)
public class NativeSelect extends AbstractSelect {
// width in characters, mimics TextField
diff --git a/src/com/vaadin/ui/Notification.java b/src/com/vaadin/ui/Notification.java
new file mode 100644
index 0000000000..bb1f874635
--- /dev/null
+++ b/src/com/vaadin/ui/Notification.java
@@ -0,0 +1,321 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import java.io.Serializable;
+
+import com.vaadin.terminal.Resource;
+
+/**
+ * A notification message, used to display temporary messages to the user - for
+ * example "Document saved", or "Save failed".
+ * <p>
+ * The notification message can consist of several parts: caption, description
+ * and icon. It is usually used with only caption - one should be wary of
+ * filling the notification with too much information.
+ * </p>
+ * <p>
+ * The notification message tries to be as unobtrusive as possible, while still
+ * drawing needed attention. There are several basic types of messages that can
+ * be used in different situations:
+ * <ul>
+ * <li>TYPE_HUMANIZED_MESSAGE fades away quickly as soon as the user uses the
+ * mouse or types something. It can be used to show fairly unimportant messages,
+ * such as feedback that an operation succeeded ("Document Saved") - the kind of
+ * messages the user ignores once the application is familiar.</li>
+ * <li>TYPE_WARNING_MESSAGE is shown for a short while after the user uses the
+ * mouse or types something. It's default style is also more noticeable than the
+ * humanized message. It can be used for messages that do not contain a lot of
+ * important information, but should be noticed by the user. Despite the name,
+ * it does not have to be a warning, but can be used instead of the humanized
+ * message whenever you want to make the message a little more noticeable.</li>
+ * <li>TYPE_ERROR_MESSAGE requires to user to click it before disappearing, and
+ * can be used for critical messages.</li>
+ * <li>TYPE_TRAY_NOTIFICATION is shown for a while in the lower left corner of
+ * the window, and can be used for "convenience notifications" that do not have
+ * to be noticed immediately, and should not interfere with the current task -
+ * for instance to show "You have a new message in your inbox" while the user is
+ * working in some other area of the application.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * In addition to the basic pre-configured types, a Notification can also be
+ * configured to show up in a custom position, for a specified time (or until
+ * clicked), and with a custom stylename. An icon can also be added.
+ * </p>
+ *
+ */
+public class Notification implements Serializable {
+ public static final int TYPE_HUMANIZED_MESSAGE = 1;
+ public static final int TYPE_WARNING_MESSAGE = 2;
+ public static final int TYPE_ERROR_MESSAGE = 3;
+ public static final int TYPE_TRAY_NOTIFICATION = 4;
+
+ public static final int POSITION_CENTERED = 1;
+ public static final int POSITION_CENTERED_TOP = 2;
+ public static final int POSITION_CENTERED_BOTTOM = 3;
+ public static final int POSITION_TOP_LEFT = 4;
+ public static final int POSITION_TOP_RIGHT = 5;
+ public static final int POSITION_BOTTOM_LEFT = 6;
+ public static final int POSITION_BOTTOM_RIGHT = 7;
+
+ public static final int DELAY_FOREVER = -1;
+ public static final int DELAY_NONE = 0;
+
+ private String caption;
+ private String description;
+ private Resource icon;
+ private int position = POSITION_CENTERED;
+ private int delayMsec = 0;
+ private String styleName;
+ private boolean htmlContentAllowed;
+
+ /**
+ * Creates a "humanized" notification message.
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption is by
+ * default rendered as html.
+ *
+ * @param caption
+ * The message to show
+ */
+ public Notification(String caption) {
+ this(caption, null, TYPE_HUMANIZED_MESSAGE);
+ }
+
+ /**
+ * Creates a notification message of the specified type.
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption is by
+ * default rendered as html.
+ *
+ * @param caption
+ * The message to show
+ * @param type
+ * The type of message
+ */
+ public Notification(String caption, int type) {
+ this(caption, null, type);
+ }
+
+ /**
+ * Creates a "humanized" notification message with a bigger caption and
+ * smaller description.
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption and
+ * description are by default rendered as html.
+ *
+ * @param caption
+ * The message caption
+ * @param description
+ * The message description
+ */
+ public Notification(String caption, String description) {
+ this(caption, description, TYPE_HUMANIZED_MESSAGE);
+ }
+
+ /**
+ * Creates a notification message of the specified type, with a bigger
+ * caption and smaller description.
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption and
+ * description are by default rendered as html.
+ *
+ * @param caption
+ * The message caption
+ * @param description
+ * The message description
+ * @param type
+ * The type of message
+ */
+ public Notification(String caption, String description, int type) {
+ this(caption, description, type, true);
+ }
+
+ /**
+ * Creates a notification message of the specified type, with a bigger
+ * caption and smaller description.
+ *
+ * Care should be taken to to avoid XSS vulnerabilities if html is allowed.
+ *
+ * @param caption
+ * The message caption
+ * @param description
+ * The message description
+ * @param type
+ * The type of message
+ * @param htmlContentAllowed
+ * Whether html in the caption and description should be
+ * displayed as html or as plain text
+ */
+ public Notification(String caption, String description, int type,
+ boolean htmlContentAllowed) {
+ this.caption = caption;
+ this.description = description;
+ this.htmlContentAllowed = htmlContentAllowed;
+ setType(type);
+ }
+
+ private void setType(int type) {
+ switch (type) {
+ case TYPE_WARNING_MESSAGE:
+ delayMsec = 1500;
+ styleName = "warning";
+ break;
+ case TYPE_ERROR_MESSAGE:
+ delayMsec = -1;
+ styleName = "error";
+ break;
+ case TYPE_TRAY_NOTIFICATION:
+ delayMsec = 3000;
+ position = POSITION_BOTTOM_RIGHT;
+ styleName = "tray";
+
+ case TYPE_HUMANIZED_MESSAGE:
+ default:
+ break;
+ }
+
+ }
+
+ /**
+ * Gets the caption part of the notification message.
+ *
+ * @return The message caption
+ */
+ public String getCaption() {
+ return caption;
+ }
+
+ /**
+ * Sets the caption part of the notification message
+ *
+ * @param caption
+ * The message caption
+ */
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
+ /**
+ * Gets the description part of the notification message.
+ *
+ * @return The message description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets the description part of the notification message.
+ *
+ * @param description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Gets the position of the notification message.
+ *
+ * @return The position
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Sets the position of the notification message.
+ *
+ * @param position
+ * The desired notification position
+ */
+ public void setPosition(int position) {
+ this.position = position;
+ }
+
+ /**
+ * Gets the icon part of the notification message.
+ *
+ * @return The message icon
+ */
+ public Resource getIcon() {
+ return icon;
+ }
+
+ /**
+ * Sets the icon part of the notification message.
+ *
+ * @param icon
+ * The desired message icon
+ */
+ public void setIcon(Resource icon) {
+ this.icon = icon;
+ }
+
+ /**
+ * Gets the delay before the notification disappears.
+ *
+ * @return the delay in msec, -1 indicates the message has to be clicked.
+ */
+ public int getDelayMsec() {
+ return delayMsec;
+ }
+
+ /**
+ * Sets the delay before the notification disappears.
+ *
+ * @param delayMsec
+ * the desired delay in msec, -1 to require the user to click the
+ * message
+ */
+ public void setDelayMsec(int delayMsec) {
+ this.delayMsec = delayMsec;
+ }
+
+ /**
+ * Sets the style name for the notification message.
+ *
+ * @param styleName
+ * The desired style name.
+ */
+ public void setStyleName(String styleName) {
+ this.styleName = styleName;
+ }
+
+ /**
+ * Gets the style name for the notification message.
+ *
+ * @return
+ */
+ public String getStyleName() {
+ return styleName;
+ }
+
+ /**
+ * Sets whether html is allowed in the caption and description. If set to
+ * true, the texts are passed to the browser as html and the developer is
+ * responsible for ensuring no harmful html is used. If set to false, the
+ * texts are passed to the browser as plain text.
+ *
+ * @param htmlContentAllowed
+ * true if the texts are used as html, false if used as plain
+ * text
+ */
+ public void setHtmlContentAllowed(boolean htmlContentAllowed) {
+ this.htmlContentAllowed = htmlContentAllowed;
+ }
+
+ /**
+ * Checks whether caption and description are interpreted as html or plain
+ * text.
+ *
+ * @return true if the texts are used as html, false if used as plain text
+ * @see #setHtmlContentAllowed(boolean)
+ */
+ public boolean isHtmlContentAllowed() {
+ return htmlContentAllowed;
+ }
+} \ No newline at end of file
diff --git a/src/com/vaadin/ui/OptionGroup.java b/src/com/vaadin/ui/OptionGroup.java
index 884e58824a..ddacc31554 100644
--- a/src/com/vaadin/ui/OptionGroup.java
+++ b/src/com/vaadin/ui/OptionGroup.java
@@ -18,12 +18,13 @@ import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VOptionGroup;
+import com.vaadin.terminal.gwt.client.ui.VOptionGroupPaintable;
/**
* Configures select to be used as an option group.
*/
@SuppressWarnings("serial")
-@ClientWidget(VOptionGroup.class)
+@ClientWidget(VOptionGroupPaintable.class)
public class OptionGroup extends AbstractSelect implements
FieldEvents.BlurNotifier, FieldEvents.FocusNotifier {
diff --git a/src/com/vaadin/ui/OrderedLayout.java b/src/com/vaadin/ui/OrderedLayout.java
deleted file mode 100644
index 474fc89867..0000000000
--- a/src/com/vaadin/ui/OrderedLayout.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.ui;
-
-import com.vaadin.terminal.PaintException;
-import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VOrderedLayout;
-import com.vaadin.ui.ClientWidget.LoadStyle;
-
-/**
- * Ordered layout.
- *
- * <code>OrderedLayout</code> is a component container, which shows the
- * subcomponents in the order of their addition in specified orientation.
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- * @deprecated Replaced by VerticalLayout/HorizontalLayout. For type checking
- * please not that VerticalLayout/HorizontalLayout do not extend
- * OrderedLayout but AbstractOrderedLayout (which also OrderedLayout
- * extends).
- */
-@SuppressWarnings("serial")
-@Deprecated
-@ClientWidget(value = VOrderedLayout.class, loadStyle = LoadStyle.EAGER)
-public class OrderedLayout extends AbstractOrderedLayout {
- /* Predefined orientations */
-
- /**
- * Components are to be laid out vertically.
- */
- public static final int ORIENTATION_VERTICAL = 0;
-
- /**
- * Components are to be laid out horizontally.
- */
- public static final int ORIENTATION_HORIZONTAL = 1;
-
- /**
- * Orientation of the layout.
- */
- private int orientation;
-
- /**
- * Creates a new ordered layout. The order of the layout is
- * <code>ORIENTATION_VERTICAL</code>.
- *
- * @deprecated Use VerticalLayout instead.
- */
- @Deprecated
- public OrderedLayout() {
- this(ORIENTATION_VERTICAL);
- }
-
- /**
- * Create a new ordered layout. The orientation of the layout is given as
- * parameters.
- *
- * @param orientation
- * the Orientation of the layout.
- *
- * @deprecated Use VerticalLayout/HorizontalLayout instead.
- */
- @Deprecated
- public OrderedLayout(int orientation) {
- this.orientation = orientation;
- if (orientation == ORIENTATION_VERTICAL) {
- setWidth(100, UNITS_PERCENTAGE);
- }
- }
-
- /**
- * Gets the orientation of the container.
- *
- * @return the Value of property orientation.
- */
- public int getOrientation() {
- return orientation;
- }
-
- /**
- * Sets the orientation of this OrderedLayout. This method should only be
- * used before initial paint.
- *
- * @param orientation
- * the New value of property orientation.
- * @deprecated Use VerticalLayout/HorizontalLayout or define orientation in
- * constructor instead
- */
- @Deprecated
- public void setOrientation(int orientation) {
- setOrientation(orientation, true);
- }
-
- /**
- * Internal method to change orientation of layout. This method should only
- * be used before initial paint.
- *
- * @param orientation
- */
- protected void setOrientation(int orientation, boolean needsRepaint) {
- // Checks the validity of the argument
- if (orientation < ORIENTATION_VERTICAL
- || orientation > ORIENTATION_HORIZONTAL) {
- throw new IllegalArgumentException();
- }
-
- this.orientation = orientation;
- if (needsRepaint) {
- requestRepaint();
- }
- }
-
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- super.paintContent(target);
-
- // Adds the orientation attributes (the default is vertical)
- if (orientation == ORIENTATION_HORIZONTAL) {
- target.addAttribute("orientation", "horizontal");
- }
-
- }
-
-}
diff --git a/src/com/vaadin/ui/Panel.java b/src/com/vaadin/ui/Panel.java
index a69413c28b..390279a62f 100644
--- a/src/com/vaadin/ui/Panel.java
+++ b/src/com/vaadin/ui/Panel.java
@@ -16,7 +16,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Scrollable;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.ui.VPanel;
+import com.vaadin.terminal.gwt.client.ui.VPanelPaintable;
import com.vaadin.ui.Component.Focusable;
import com.vaadin.ui.themes.Reindeer;
import com.vaadin.ui.themes.Runo;
@@ -30,12 +30,12 @@ import com.vaadin.ui.themes.Runo;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VPanel.class)
+@ClientWidget(VPanelPaintable.class)
public class Panel extends AbstractComponentContainer implements Scrollable,
ComponentContainer.ComponentAttachListener,
ComponentContainer.ComponentDetachListener, Action.Notifier, Focusable {
- private static final String CLICK_EVENT = VPanel.CLICK_EVENT_IDENTIFIER;
+ private static final String CLICK_EVENT = VPanelPaintable.CLICK_EVENT_IDENTIFIER;
/**
* Removes extra decorations from the Panel.
@@ -559,6 +559,7 @@ public class Panel extends AbstractComponentContainer implements Scrollable,
/*
* ACTIONS
*/
+ @Override
protected ActionManager getActionManager() {
if (actionManager == null) {
actionManager = new ActionManager(this);
diff --git a/src/com/vaadin/ui/PasswordField.java b/src/com/vaadin/ui/PasswordField.java
index 99874147d5..d5be4f378d 100644
--- a/src/com/vaadin/ui/PasswordField.java
+++ b/src/com/vaadin/ui/PasswordField.java
@@ -4,13 +4,13 @@
package com.vaadin.ui;
import com.vaadin.data.Property;
-import com.vaadin.terminal.gwt.client.ui.VPasswordField;
+import com.vaadin.terminal.gwt.client.ui.VPasswordFieldPaintable;
/**
* A field that is used to enter secret text information like passwords. The
* entered text is not displayed on the screen.
*/
-@ClientWidget(VPasswordField.class)
+@ClientWidget(VPasswordFieldPaintable.class)
public class PasswordField extends AbstractTextField {
/**
diff --git a/src/com/vaadin/ui/PopupView.java b/src/com/vaadin/ui/PopupView.java
index fcad727510..5637ef69d7 100644
--- a/src/com/vaadin/ui/PopupView.java
+++ b/src/com/vaadin/ui/PopupView.java
@@ -10,7 +10,7 @@ import java.util.Map;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VPopupView;
+import com.vaadin.terminal.gwt.client.ui.VPopupViewPaintable;
/**
*
@@ -22,7 +22,7 @@ import com.vaadin.terminal.gwt.client.ui.VPopupView;
* @author Vaadin Ltd.
*/
@SuppressWarnings("serial")
-@ClientWidget(VPopupView.class)
+@ClientWidget(VPopupViewPaintable.class)
public class PopupView extends AbstractComponentContainer {
private Content content;
diff --git a/src/com/vaadin/ui/ProgressIndicator.java b/src/com/vaadin/ui/ProgressIndicator.java
index 405ff2b52f..9152a3adab 100644
--- a/src/com/vaadin/ui/ProgressIndicator.java
+++ b/src/com/vaadin/ui/ProgressIndicator.java
@@ -8,7 +8,7 @@ import com.vaadin.data.Property;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VProgressIndicator;
+import com.vaadin.terminal.gwt.client.ui.VProgressIndicatorPaintable;
/**
* <code>ProgressIndicator</code> is component that shows user state of a
@@ -25,8 +25,8 @@ import com.vaadin.terminal.gwt.client.ui.VProgressIndicator;
* @since 4
*/
@SuppressWarnings("serial")
-@ClientWidget(VProgressIndicator.class)
-public class ProgressIndicator extends AbstractField implements Property,
+@ClientWidget(VProgressIndicatorPaintable.class)
+public class ProgressIndicator extends AbstractField<Number> implements
Property.Viewer, Property.ValueChangeListener {
/**
@@ -125,11 +125,12 @@ public class ProgressIndicator extends AbstractField implements Property,
* @see com.vaadin.ui.AbstractField#getValue()
*/
@Override
- public Object getValue() {
+ public Number getValue() {
if (dataSource == null) {
throw new IllegalStateException("Datasource must be set");
}
- return dataSource.getValue();
+ // TODO conversions to eliminate cast
+ return (Number) dataSource.getValue();
}
/**
@@ -138,7 +139,7 @@ public class ProgressIndicator extends AbstractField implements Property,
*
* @param newValue
* the New value of the ProgressIndicator.
- * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object)
+ * @see com.vaadin.ui.AbstractField#setValue()
*/
@Override
public void setValue(Object newValue) {
@@ -149,21 +150,10 @@ public class ProgressIndicator extends AbstractField implements Property,
}
/**
- * @see com.vaadin.ui.AbstractField#toString()
- */
- @Override
- public String toString() {
- if (dataSource == null) {
- throw new IllegalStateException("Datasource must be set");
- }
- return dataSource.toString();
- }
-
- /**
* @see com.vaadin.ui.AbstractField#getType()
*/
@Override
- public Class<?> getType() {
+ public Class<? extends Number> getType() {
if (dataSource == null) {
throw new IllegalStateException("Datasource must be set");
}
diff --git a/src/com/vaadin/ui/RichTextArea.java b/src/com/vaadin/ui/RichTextArea.java
index f4d88edc78..240063caf3 100644
--- a/src/com/vaadin/ui/RichTextArea.java
+++ b/src/com/vaadin/ui/RichTextArea.java
@@ -10,7 +10,7 @@ import java.util.Map;
import com.vaadin.data.Property;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea;
+import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextAreaPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -20,8 +20,8 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* {@link RichTextArea} may produce unexpected results as formatting is counted
* into length of field.
*/
-@ClientWidget(value = VRichTextArea.class, loadStyle = LoadStyle.LAZY)
-public class RichTextArea extends AbstractField {
+@ClientWidget(value = VRichTextAreaPaintable.class, loadStyle = LoadStyle.LAZY)
+public class RichTextArea extends AbstractField<String> {
/**
* Value formatter used to format the string contents.
@@ -129,6 +129,7 @@ public class RichTextArea extends AbstractField {
public void setReadOnly(boolean readOnly) {
super.setReadOnly(readOnly);
// IE6 cannot support multi-classname selectors properly
+ // TODO Can be optimized now that support for I6 is dropped
if (readOnly) {
addStyleName("v-richtextarea-readonly");
} else {
@@ -175,8 +176,8 @@ public class RichTextArea extends AbstractField {
}
@Override
- public Object getValue() {
- Object v = super.getValue();
+ public String getValue() {
+ String v = super.getValue();
if (format == null || v == null) {
return v;
}
@@ -221,7 +222,7 @@ public class RichTextArea extends AbstractField {
}
@Override
- public Class getType() {
+ public Class<String> getType() {
return String.class;
}
@@ -342,7 +343,7 @@ public class RichTextArea extends AbstractField {
@Override
protected boolean isEmpty() {
- return super.isEmpty() || toString().length() == 0;
+ return super.isEmpty() || getValue().length() == 0;
}
}
diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java
new file mode 100644
index 0000000000..7fd4a79458
--- /dev/null
+++ b/src/com/vaadin/ui/Root.java
@@ -0,0 +1,1539 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.vaadin.Application;
+import com.vaadin.annotations.EagerInit;
+import com.vaadin.event.Action;
+import com.vaadin.event.Action.Handler;
+import com.vaadin.event.ActionManager;
+import com.vaadin.event.MouseEvents.ClickEvent;
+import com.vaadin.event.MouseEvents.ClickListener;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedRequest.BrowserDetails;
+import com.vaadin.terminal.gwt.client.MouseEventDetails;
+import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.tools.ReflectTools;
+import com.vaadin.ui.Window.CloseListener;
+
+/**
+ * The topmost component in any component hierarchy. There is one root for every
+ * Vaadin instance in a browser window. A root may either represent an entire
+ * browser window (or tab) or some part of a html page where a Vaadin
+ * application is embedded.
+ * <p>
+ * The root is the server side entry point for various client side features that
+ * are not represented as components added to a layout, e.g notifications, sub
+ * windows, and executing javascript in the browser.
+ * </p>
+ * <p>
+ * When a new application instance is needed, typically because the user opens
+ * the application in a browser window,
+ * {@link Application#gerRoot(WrappedRequest)} is invoked to get a root. That
+ * method does by default create a root according to the
+ * {@value Application#ROOT_PARAMETER} parameter from web.xml.
+ * </p>
+ * <p>
+ * After a root has been created by the application, it is initialized using
+ * {@link #init(WrappedRequest)}. This method is intended to be overridden by
+ * the developer to add components to the user interface and initialize
+ * non-component functionality. The component hierarchy is initialized by
+ * passing a {@link ComponentContainer} with the main layout of the view to
+ * {@link #setContent(ComponentContainer)}.
+ * </p>
+ * <p>
+ * If a {@link EagerInit} annotation is present on a class extending
+ * <code>Root</code>, the framework will use a faster initialization method
+ * which will not ensure that {@link BrowserDetails} are present in the
+ * {@link WrappedRequest} passed to the init method.
+ * </p>
+ *
+ * @see #init(WrappedRequest)
+ * @see Application#getRoot(WrappedRequest)
+ *
+ * @since 7.0
+ */
+// @ClientWidget(VView.class) - Can't have annotation because of eager
+// classloaders in application servers and hard coded logic in client side code
+public abstract class Root extends AbstractComponentContainer implements
+ Action.Container, Action.Notifier {
+
+ /**
+ * Listener that gets notified when the size of the browser window
+ * containing the root has changed.
+ *
+ * @see Root#addListener(BrowserWindowResizeListener)
+ */
+ public interface BrowserWindowResizeListener extends Serializable {
+ /**
+ * Invoked when the browser window containing a Root has been resized.
+ *
+ * @param event
+ * a browser window resize event
+ */
+ public void browserWindowResized(BrowserWindowResizeEvent event);
+ }
+
+ /**
+ * Event that is fired when a browser window containing a root is resized.
+ */
+ public class BrowserWindowResizeEvent extends Component.Event {
+
+ private final int width;
+ private final int height;
+
+ /**
+ * Creates a new event
+ *
+ * @param source
+ * the root for which the browser window has been resized
+ * @param width
+ * the new width of the browser window
+ * @param height
+ * the new height of the browser window
+ */
+ public BrowserWindowResizeEvent(Root source, int width, int height) {
+ super(source);
+ this.width = width;
+ this.height = height;
+ }
+
+ @Override
+ public Root getSource() {
+ return (Root) super.getSource();
+ }
+
+ /**
+ * Gets the new browser window height
+ *
+ * @return an integer with the new pixel height of the browser window
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Gets the new browser window width
+ *
+ * @return an integer with the new pixel width of the browser window
+ */
+ public int getWidth() {
+ return width;
+ }
+ }
+
+ private static final Method BROWSWER_RESIZE_METHOD = ReflectTools
+ .findMethod(BrowserWindowResizeListener.class,
+ "browserWindowResized", BrowserWindowResizeEvent.class);
+
+ /**
+ * Listener that listens changes in URI fragment.
+ */
+ public interface FragmentChangedListener extends Serializable {
+ public void fragmentChanged(FragmentChangedEvent event);
+ }
+
+ /**
+ * Event fired when uri fragment changes.
+ */
+ public class FragmentChangedEvent extends Component.Event {
+
+ /**
+ * The new uri fragment
+ */
+ private final String fragment;
+
+ /**
+ * Creates a new instance of UriFragmentReader change event.
+ *
+ * @param source
+ * the Source of the event.
+ */
+ public FragmentChangedEvent(Root source, String fragment) {
+ super(source);
+ this.fragment = fragment;
+ }
+
+ /**
+ * Gets the root in which the fragment has changed.
+ *
+ * @return the root in which the fragment has changed
+ */
+ public Root getRoot() {
+ return (Root) getComponent();
+ }
+
+ /**
+ * Get the new fragment
+ *
+ * @return the new fragment
+ */
+ public String getFragment() {
+ return fragment;
+ }
+ }
+
+ /**
+ * Helper class to emulate the main window from Vaadin 6 using roots. This
+ * class should be used in the same way as Window used as a browser level
+ * window in Vaadin 6 with {@link com.vaadin.Application.LegacyApplication}
+ */
+ @Deprecated
+ @EagerInit
+ public static class LegacyWindow extends Root {
+ private String name;
+
+ /**
+ * Create a new legacy window
+ */
+ public LegacyWindow() {
+ super();
+ }
+
+ /**
+ * Creates a new legacy window with the given caption
+ *
+ * @param caption
+ * the caption of the window
+ */
+ public LegacyWindow(String caption) {
+ super(caption);
+ }
+
+ /**
+ * Creates a legacy window with the given caption and content layout
+ *
+ * @param caption
+ * @param content
+ */
+ public LegacyWindow(String caption, ComponentContainer content) {
+ super(caption, content);
+ }
+
+ @Override
+ protected void init(WrappedRequest request) {
+ // Just empty
+ }
+
+ /**
+ * Gets the unique name of the window. The name of the window is used to
+ * uniquely identify it.
+ * <p>
+ * The name also determines the URL that can be used for direct access
+ * to a window. All windows can be accessed through
+ * {@code http://host:port/app/win} where {@code http://host:port/app}
+ * is the application URL (as returned by {@link Application#getURL()}
+ * and {@code win} is the window name.
+ * </p>
+ * <p>
+ * Note! Portlets do not support direct window access through URLs.
+ * </p>
+ *
+ * @return the Name of the Window.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the unique name of the window. The name of the window is used to
+ * uniquely identify it inside the application.
+ * <p>
+ * The name also determines the URL that can be used for direct access
+ * to a window. All windows can be accessed through
+ * {@code http://host:port/app/win} where {@code http://host:port/app}
+ * is the application URL (as returned by {@link Application#getURL()}
+ * and {@code win} is the window name.
+ * </p>
+ * <p>
+ * This method can only be called before the window is added to an
+ * application.
+ * <p>
+ * Note! Portlets do not support direct window access through URLs.
+ * </p>
+ *
+ * @param name
+ * the new name for the window or null if the application
+ * should automatically assign a name to it
+ * @throws IllegalStateException
+ * if the window is attached to an application
+ */
+ public void setName(String name) {
+ this.name = name;
+ // The name can not be changed in application
+ if (getApplication() != null) {
+ throw new IllegalStateException(
+ "Window name can not be changed while "
+ + "the window is in application");
+ }
+
+ }
+
+ /**
+ * Gets the full URL of the window. The returned URL is window specific
+ * and can be used to directly refer to the window.
+ * <p>
+ * Note! This method can not be used for portlets.
+ * </p>
+ *
+ * @return the URL of the window or null if the window is not attached
+ * to an application
+ */
+ public URL getURL() {
+ Application application = getApplication();
+ if (application == null) {
+ return null;
+ }
+
+ try {
+ return new URL(application.getURL(), getName() + "/");
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(
+ "Internal problem getting window URL, please report");
+ }
+ }
+ }
+
+ private static final Method FRAGMENT_CHANGED_METHOD;
+
+ static {
+ try {
+ FRAGMENT_CHANGED_METHOD = FragmentChangedListener.class
+ .getDeclaredMethod("fragmentChanged",
+ new Class[] { FragmentChangedEvent.class });
+ } catch (final java.lang.NoSuchMethodException e) {
+ // This should never happen
+ throw new java.lang.RuntimeException(
+ "Internal error finding methods in FragmentChangedListener");
+ }
+ }
+
+ /**
+ * A border style used for opening resources in a window without a border.
+ */
+ public static final int BORDER_NONE = 0;
+
+ /**
+ * A border style used for opening resources in a window with a minimal
+ * border.
+ */
+ public static final int BORDER_MINIMAL = 1;
+
+ /**
+ * A border style that indicates that the default border style should be
+ * used when opening resources.
+ */
+ public static final int BORDER_DEFAULT = 2;
+
+ /**
+ * The container in which the component hierarchy of the root starts.
+ */
+ private ComponentContainer content;
+
+ /**
+ * The application to which this root belongs
+ */
+ private Application application;
+
+ /**
+ * A list of notifications that are waiting to be sent to the client.
+ * Cleared (set to null) when the notifications have been sent.
+ */
+ private List<Notification> notifications;
+
+ /**
+ * A list of javascript commands that are waiting to be sent to the client.
+ * Cleared (set to null) when the commands have been sent.
+ */
+ private List<String> jsExecQueue = null;
+
+ /**
+ * List of windows in this root.
+ */
+ private final LinkedHashSet<Window> windows = new LinkedHashSet<Window>();
+
+ /**
+ * Resources to be opened automatically on next repaint. The list is
+ * automatically cleared when it has been sent to the client.
+ */
+ private final LinkedList<OpenResource> openList = new LinkedList<OpenResource>();
+
+ /**
+ * The component that should be scrolled into view after the next repaint.
+ * Null if nothing should be scrolled into view.
+ */
+ private Component scrollIntoView;
+
+ /**
+ * The id of this root, used to find the server side instance of the root
+ * form which a request originates. A negative value indicates that the root
+ * id has not yet been assigned by the Application.
+ *
+ * @see Application#nextRootId
+ */
+ private int rootId = -1;
+
+ /**
+ * Keeps track of the Actions added to this component, and manages the
+ * painting and handling as well.
+ */
+ protected ActionManager actionManager;
+
+ /**
+ * Thread local for keeping track of the current root.
+ */
+ private static final ThreadLocal<Root> currentRoot = new ThreadLocal<Root>();
+
+ private int browserWindowWidth = -1;
+ private int browserWindowHeight = -1;
+
+ /** Identifies the click event */
+ private static final String CLICK_EVENT_ID = VView.CLICK_EVENT_ID;
+
+ /**
+ * Creates a new empty root without a caption. This root will have a
+ * {@link VerticalLayout} with margins enabled as its content.
+ */
+ public Root() {
+ // Nothing to do here?
+ }
+
+ /**
+ * Creates a new root with the given component container as its content.
+ *
+ * @param content
+ * the content container to use as this roots content.
+ *
+ * @see #setContent(ComponentContainer)
+ */
+ public Root(ComponentContainer content) {
+ setContent(content);
+ }
+
+ /**
+ * Creates a new empty root with the given caption. This root will have a
+ * {@link VerticalLayout} with margins enabled as its content.
+ *
+ * @param caption
+ * the caption of the root, used as the page title if there's
+ * nothing but the application on the web page
+ *
+ * @see #setCaption(String)
+ */
+ public Root(String caption) {
+ setCaption(caption);
+ }
+
+ /**
+ * Creates a new root with the given caption and content.
+ *
+ * @param caption
+ * the caption of the root, used as the page title if there's
+ * nothing but the application on the web page
+ * @param content
+ * the content container to use as this roots content.
+ *
+ * @see #setContent(ComponentContainer)
+ * @see #setCaption(String)
+ */
+ public Root(String caption, ComponentContainer content) {
+ this(content);
+ setCaption(caption);
+ }
+
+ /**
+ * Overridden to return a value instead of referring to the parent.
+ *
+ * @return this root
+ *
+ * @see com.vaadin.ui.AbstractComponent#getRoot()
+ */
+ @Override
+ public Root getRoot() {
+ return this;
+ }
+
+ public void replaceComponent(Component oldComponent, Component newComponent) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Application getApplication() {
+ return application;
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ // Open requested resource
+ synchronized (openList) {
+ if (!openList.isEmpty()) {
+ for (final Iterator<OpenResource> i = openList.iterator(); i
+ .hasNext();) {
+ (i.next()).paintContent(target);
+ }
+ openList.clear();
+ }
+ }
+
+ ComponentContainer content = getContent();
+ if (content != null) {
+ content.paint(target);
+ }
+
+ // Paint subwindows
+ for (final Iterator<Window> i = windows.iterator(); i.hasNext();) {
+ final Window w = i.next();
+ w.paint(target);
+ }
+
+ // Paint notifications
+ if (notifications != null) {
+ target.startTag("notifications");
+ for (final Iterator<Notification> it = notifications.iterator(); it
+ .hasNext();) {
+ final Notification n = it.next();
+ target.startTag("notification");
+ if (n.getCaption() != null) {
+ target.addAttribute("caption", n.getCaption());
+ }
+ if (n.getDescription() != null) {
+ target.addAttribute("message", n.getDescription());
+ }
+ if (n.getIcon() != null) {
+ target.addAttribute("icon", n.getIcon());
+ }
+ if (!n.isHtmlContentAllowed()) {
+ target.addAttribute(
+ VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, true);
+ }
+ target.addAttribute("position", n.getPosition());
+ target.addAttribute("delay", n.getDelayMsec());
+ if (n.getStyleName() != null) {
+ target.addAttribute("style", n.getStyleName());
+ }
+ target.endTag("notification");
+ }
+ target.endTag("notifications");
+ notifications = null;
+ }
+
+ // Add executable javascripts if needed
+ if (jsExecQueue != null) {
+ for (String script : jsExecQueue) {
+ target.startTag("execJS");
+ target.addAttribute("script", script);
+ target.endTag("execJS");
+ }
+ jsExecQueue = null;
+ }
+
+ if (scrollIntoView != null) {
+ target.addAttribute("scrollTo", scrollIntoView);
+ scrollIntoView = null;
+ }
+
+ if (pendingFocus != null) {
+ // ensure focused component is still attached to this main window
+ if (pendingFocus.getRoot() == this
+ || (pendingFocus.getRoot() != null && pendingFocus
+ .getRoot().getParent() == this)) {
+ target.addAttribute("focused", pendingFocus);
+ }
+ pendingFocus = null;
+ }
+
+ if (actionManager != null) {
+ actionManager.paintActions(null, target);
+ }
+
+ if (fragment != null) {
+ target.addAttribute(VView.FRAGMENT_VARIABLE, fragment);
+ }
+
+ if (isResizeLazy()) {
+ target.addAttribute(VView.RESIZE_LAZY, true);
+ }
+ }
+
+ /**
+ * Fire a click event to all click listeners.
+ *
+ * @param object
+ * The raw "value" of the variable change from the client side.
+ */
+ private void fireClick(Map<String, Object> parameters) {
+ MouseEventDetails mouseDetails = MouseEventDetails
+ .deSerialize((String) parameters.get("mouseDetails"));
+ fireEvent(new ClickEvent(this, mouseDetails));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void changeVariables(Object source, Map<String, Object> variables) {
+ super.changeVariables(source, variables);
+
+ if (variables.containsKey(CLICK_EVENT_ID)) {
+ fireClick((Map<String, Object>) variables.get(CLICK_EVENT_ID));
+ }
+
+ // Actions
+ if (actionManager != null) {
+ actionManager.handleActions(variables, this);
+ }
+
+ if (variables.containsKey(VView.FRAGMENT_VARIABLE)) {
+ String fragment = (String) variables.get(VView.FRAGMENT_VARIABLE);
+ setFragment(fragment, true);
+ }
+
+ boolean sendResizeEvent = false;
+ if (variables.containsKey("height")) {
+ browserWindowHeight = ((Integer) variables.get("height"))
+ .intValue();
+ sendResizeEvent = true;
+ }
+ if (variables.containsKey("width")) {
+ browserWindowWidth = ((Integer) variables.get("width")).intValue();
+ sendResizeEvent = true;
+ }
+ if (sendResizeEvent) {
+ fireEvent(new BrowserWindowResizeEvent(this, browserWindowWidth,
+ browserWindowHeight));
+ }
+ }
+
+ public Iterator<Component> getComponentIterator() {
+ return Collections.singleton((Component) getContent()).iterator();
+ }
+
+ /**
+ * Sets the application to which this root is assigned. It is not legal to
+ * change the application once it has been set nor to set a
+ * <code>null</code> application.
+ * <p>
+ * This method is mainly intended for internal use by the framework.
+ * </p>
+ *
+ * @param application
+ * the application to set
+ *
+ * @throws IllegalStateException
+ * if the application has already been set
+ *
+ * @see #getApplication()
+ */
+ public void setApplication(Application application) {
+ if ((application == null) == (this.application == null)) {
+ throw new IllegalStateException("Application has already been set");
+ } else {
+ this.application = application;
+ }
+
+ if (application != null) {
+ attach();
+ } else {
+ detach();
+ }
+ }
+
+ /**
+ * Sets the id of this root within its application. The root id is used to
+ * route requests to the right root.
+ * <p>
+ * This method is mainly intended for internal use by the framework.
+ * </p>
+ *
+ * @param rootId
+ * the id of this root
+ *
+ * @throws IllegalStateException
+ * if the root id has already been set
+ *
+ * @see #getRootId()
+ */
+ public void setRootId(int rootId) {
+ if (this.rootId != -1) {
+ throw new IllegalStateException("Root id has already been defined");
+ }
+ this.rootId = rootId;
+ }
+
+ /**
+ * Gets the id of the root, used to identify this root within its
+ * application when processing requests. The root id should be present in
+ * every request to the server that originates from this root.
+ * {@link Application#getRootForRequest(WrappedRequest)} uses this id to
+ * find the route to which the request belongs.
+ *
+ * @return
+ */
+ public int getRootId() {
+ return rootId;
+ }
+
+ /**
+ * Adds a window as a subwindow inside this root. To open a new browser
+ * window or tab, you should instead use {@link open(Resource)} with an url
+ * pointing to this application and ensure
+ * {@link Application#getRoot(WrappedRequest)} returns an appropriate root
+ * for the request.
+ *
+ * @param window
+ * @throws IllegalArgumentException
+ * if the window is already added to an application
+ * @throws NullPointerException
+ * if the given <code>Window</code> is <code>null</code>.
+ */
+ public void addWindow(Window window) throws IllegalArgumentException,
+ NullPointerException {
+
+ if (window == null) {
+ throw new NullPointerException("Argument must not be null");
+ }
+
+ if (window.getApplication() != null) {
+ throw new IllegalArgumentException(
+ "Window is already attached to an application.");
+ }
+
+ attachWindow(window);
+ }
+
+ /**
+ * Helper method to attach a window.
+ *
+ * @param w
+ * the window to add
+ */
+ private void attachWindow(Window w) {
+ windows.add(w);
+ w.setParent(this);
+ requestRepaint();
+ }
+
+ /**
+ * Remove the given subwindow from this root.
+ *
+ * Since Vaadin 6.5, {@link CloseListener}s are called also when explicitly
+ * removing a window by calling this method.
+ *
+ * Since Vaadin 6.5, returns a boolean indicating if the window was removed
+ * or not.
+ *
+ * @param window
+ * Window to be removed.
+ * @return true if the subwindow was removed, false otherwise
+ */
+ public boolean removeWindow(Window window) {
+ if (!windows.remove(window)) {
+ // Window window is not a subwindow of this root.
+ return false;
+ }
+ window.setParent(null);
+ window.fireClose();
+ requestRepaint();
+
+ return true;
+ }
+
+ /**
+ * Gets all the windows added to this root.
+ *
+ * @return an unmodifiable collection of windows
+ */
+ public Collection<Window> getWindows() {
+ return Collections.unmodifiableCollection(windows);
+ }
+
+ @Override
+ public void focus() {
+ super.focus();
+ }
+
+ /**
+ * Component that should be focused after the next repaint. Null if no focus
+ * change should take place.
+ */
+ private Focusable pendingFocus;
+
+ /**
+ * The current URI fragment.
+ */
+ private String fragment;
+
+ private boolean resizeLazy = false;
+
+ /**
+ * This method is used by Component.Focusable objects to request focus to
+ * themselves. Focus renders must be handled at window level (instead of
+ * Component.Focusable) due we want the last focused component to be focused
+ * in client too. Not the one that is rendered last (the case we'd get if
+ * implemented in Focusable only).
+ *
+ * To focus component from Vaadin application, use Focusable.focus(). See
+ * {@link Focusable}.
+ *
+ * @param focusable
+ * to be focused on next paint
+ */
+ public void setFocusedComponent(Focusable focusable) {
+ pendingFocus = focusable;
+ requestRepaint();
+ }
+
+ /**
+ * Shows a notification message on the middle of the root. The message
+ * automatically disappears ("humanized message").
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption is
+ * rendered as html.
+ *
+ * @see #showNotification(Notification)
+ * @see Notification
+ *
+ * @param caption
+ * The message
+ */
+ public void showNotification(String caption) {
+ addNotification(new Notification(caption));
+ }
+
+ /**
+ * Shows a notification message the root. The position and behavior of the
+ * message depends on the type, which is one of the basic types defined in
+ * {@link Notification}, for instance Notification.TYPE_WARNING_MESSAGE.
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption is
+ * rendered as html.
+ *
+ * @see #showNotification(Notification)
+ * @see Notification
+ *
+ * @param caption
+ * The message
+ * @param type
+ * The message type
+ */
+ public void showNotification(String caption, int type) {
+ addNotification(new Notification(caption, type));
+ }
+
+ /**
+ * Shows a notification consisting of a bigger caption and a smaller
+ * description on the middle of the root. The message automatically
+ * disappears ("humanized message").
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption and
+ * description are rendered as html.
+ *
+ * @see #showNotification(Notification)
+ * @see Notification
+ *
+ * @param caption
+ * The caption of the message
+ * @param description
+ * The message description
+ *
+ */
+ public void showNotification(String caption, String description) {
+ addNotification(new Notification(caption, description));
+ }
+
+ /**
+ * Shows a notification consisting of a bigger caption and a smaller
+ * description. The position and behavior of the message depends on the
+ * type, which is one of the basic types defined in {@link Notification},
+ * for instance Notification.TYPE_WARNING_MESSAGE.
+ *
+ * Care should be taken to to avoid XSS vulnerabilities as the caption and
+ * description are rendered as html.
+ *
+ * @see #showNotification(Notification)
+ * @see Notification
+ *
+ * @param caption
+ * The caption of the message
+ * @param description
+ * The message description
+ * @param type
+ * The message type
+ */
+ public void showNotification(String caption, String description, int type) {
+ addNotification(new Notification(caption, description, type));
+ }
+
+ /**
+ * Shows a notification consisting of a bigger caption and a smaller
+ * description. The position and behavior of the message depends on the
+ * type, which is one of the basic types defined in {@link Notification},
+ * for instance Notification.TYPE_WARNING_MESSAGE.
+ *
+ * Care should be taken to avoid XSS vulnerabilities if html content is
+ * allowed.
+ *
+ * @see #showNotification(Notification)
+ * @see Notification
+ *
+ * @param caption
+ * The message caption
+ * @param description
+ * The message description
+ * @param type
+ * The type of message
+ * @param htmlContentAllowed
+ * Whether html in the caption and description should be
+ * displayed as html or as plain text
+ */
+ public void showNotification(String caption, String description, int type,
+ boolean htmlContentAllowed) {
+ addNotification(new Notification(caption, description, type,
+ htmlContentAllowed));
+ }
+
+ /**
+ * Shows a notification message.
+ *
+ * @see Notification
+ * @see #showNotification(String)
+ * @see #showNotification(String, int)
+ * @see #showNotification(String, String)
+ * @see #showNotification(String, String, int)
+ *
+ * @param notification
+ * The notification message to show
+ */
+ public void showNotification(Notification notification) {
+ addNotification(notification);
+ }
+
+ /**
+ * Internal helper method to actually add a notification.
+ *
+ * @param notification
+ * the notification to add
+ */
+ private void addNotification(Notification notification) {
+ if (notifications == null) {
+ notifications = new LinkedList<Notification>();
+ }
+ notifications.add(notification);
+ requestRepaint();
+ }
+
+ /**
+ * Executes JavaScript in this root.
+ *
+ * <p>
+ * This method allows one to inject javascript from the server to client. A
+ * client implementation is not required to implement this functionality,
+ * but currently all web-based clients do implement this.
+ * </p>
+ *
+ * <p>
+ * Executing javascript this way often leads to cross-browser compatibility
+ * issues and regressions that are hard to resolve. Use of this method
+ * should be avoided and instead it is recommended to create new widgets
+ * with GWT. For more info on creating own, reusable client-side widgets in
+ * Java, read the corresponding chapter in Book of Vaadin.
+ * </p>
+ *
+ * @param script
+ * JavaScript snippet that will be executed.
+ */
+ public void executeJavaScript(String script) {
+ if (jsExecQueue == null) {
+ jsExecQueue = new ArrayList<String>();
+ }
+
+ jsExecQueue.add(script);
+
+ requestRepaint();
+ }
+
+ /**
+ * Scrolls any component between the component and root to a suitable
+ * position so the component is visible to the user. The given component
+ * must belong to this root.
+ *
+ * @param component
+ * the component to be scrolled into view
+ * @throws IllegalArgumentException
+ * if {@code component} does not belong to this root
+ */
+ public void scrollIntoView(Component component)
+ throws IllegalArgumentException {
+ if (component.getRoot() != this) {
+ throw new IllegalArgumentException(
+ "The component where to scroll must belong to this root.");
+ }
+ scrollIntoView = component;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the content of this root. The content is a component container that
+ * serves as the outermost item of the visual contents of this root.
+ *
+ * @return a component container to use as content
+ *
+ * @see #setContent(ComponentContainer)
+ * @see #createDefaultLayout()
+ */
+ public ComponentContainer getContent() {
+ if (content == null) {
+ setContent(createDefaultLayout());
+ }
+ return content;
+ }
+
+ /**
+ * Helper method to create the default content layout that is used if no
+ * content has not been explicitly defined.
+ *
+ * @return a newly created layout
+ */
+ private static VerticalLayout createDefaultLayout() {
+ VerticalLayout layout = new VerticalLayout();
+ layout.setMargin(true);
+ return layout;
+ }
+
+ /**
+ * Sets the content of this root. The content is a component container that
+ * serves as the outermost item of the visual contents of this root. If no
+ * content has been set, a {@link VerticalLayout} with margins enabled will
+ * be used by default - see {@link #createDefaultLayout()}. The content can
+ * also be set in a constructor.
+ *
+ * @return a component container to use as content
+ *
+ * @see #Root(ComponentContainer)
+ * @see #createDefaultLayout()
+ */
+ public void setContent(ComponentContainer content) {
+ if (this.content != null) {
+ super.removeComponent(this.content);
+ }
+ this.content = content;
+ if (content != null) {
+ super.addComponent(content);
+ }
+ }
+
+ /**
+ * Adds a component to this root. The component is not added directly to the
+ * root, but instead to the content container ({@link #getContent()}).
+ *
+ * @param component
+ * the component to add to this root
+ *
+ * @see #getContent()
+ */
+ @Override
+ public void addComponent(Component component) {
+ getContent().addComponent(component);
+ }
+
+ /**
+ * This implementation removes the component from the content container (
+ * {@link #getContent()}) instead of from the actual root.
+ */
+ @Override
+ public void removeComponent(Component component) {
+ getContent().removeComponent(component);
+ }
+
+ /**
+ * This implementation removes the components from the content container (
+ * {@link #getContent()}) instead of from the actual root.
+ */
+ @Override
+ public void removeAllComponents() {
+ getContent().removeAllComponents();
+ }
+
+ /**
+ * Internal initialization method, should not be overridden. This method is
+ * not declared as final because that would break compatibility with e.g.
+ * CDI.
+ *
+ * @param request
+ * the initialization request
+ */
+ public void doInit(WrappedRequest request) {
+ BrowserDetails browserDetails = request.getBrowserDetails();
+ if (browserDetails != null) {
+ fragment = browserDetails.getUriFragment();
+ }
+
+ // Call the init overridden by the application developer
+ init(request);
+ }
+
+ /**
+ * Initializes this root. This method is intended to be overridden by
+ * subclasses to build the view and configure non-component functionality.
+ * Performing the initialization in a constructor is not suggested as the
+ * state of the root is not properly set up when the constructor is invoked.
+ * <p>
+ * The {@link WrappedRequest} can be used to get information about the
+ * request that caused this root to be created. By default, the
+ * {@link BrowserDetails} will be available in the request. If the browser
+ * details are not required, loading the application in the browser can take
+ * some shortcuts giving a faster initial rendering. This can be indicated
+ * by adding the {@link EagerInit} annotation to the Root class.
+ * </p>
+ *
+ * @param request
+ * the wrapped request that caused this root to be created
+ */
+ protected abstract void init(WrappedRequest request);
+
+ /**
+ * Sets the thread local for the current root. This method is used by the
+ * framework to set the current application whenever a new request is
+ * processed and it is cleared when the request has been processed.
+ * <p>
+ * The application developer can also use this method to define the current
+ * root outside the normal request handling, e.g. when initiating custom
+ * background threads.
+ * </p>
+ *
+ * @param root
+ * the root to register as the current root
+ *
+ * @see #getCurrentRoot()
+ * @see ThreadLocal
+ */
+ public static void setCurrentRoot(Root root) {
+ currentRoot.set(root);
+ }
+
+ /**
+ * Gets the currently used root. The current root is automatically defined
+ * when processing requests to the server. In other cases, (e.g. from
+ * background threads), the current root is not automatically defined.
+ *
+ * @return the current root instance if available, otherwise
+ * <code>null</code>
+ *
+ * @see #setCurrentRoot(Root)
+ */
+ public static Root getCurrentRoot() {
+ return currentRoot.get();
+ }
+
+ /**
+ * Opens the given resource in this root. The contents of this Root is
+ * replaced by the {@code Resource}.
+ *
+ * @param resource
+ * the resource to show in this root
+ */
+ public void open(Resource resource) {
+ synchronized (openList) {
+ if (!openList.contains(resource)) {
+ openList.add(new OpenResource(resource, null, -1, -1,
+ BORDER_DEFAULT));
+ }
+ }
+ requestRepaint();
+ }
+
+ /* ********************************************************************* */
+
+ /**
+ * Opens the given resource in a window with the given name.
+ * <p>
+ * The supplied {@code windowName} is used as the target name in a
+ * window.open call in the client. This means that special values such as
+ * "_blank", "_self", "_top", "_parent" have special meaning. An empty or
+ * <code>null</code> window name is also a special case.
+ * </p>
+ * <p>
+ * "", null and "_self" as {@code windowName} all causes the resource to be
+ * opened in the current window, replacing any old contents. For
+ * downloadable content you should avoid "_self" as "_self" causes the
+ * client to skip rendering of any other changes as it considers them
+ * irrelevant (the page will be replaced by the resource). This can speed up
+ * the opening of a resource, but it might also put the client side into an
+ * inconsistent state if the window content is not completely replaced e.g.,
+ * if the resource is downloaded instead of displayed in the browser.
+ * </p>
+ * <p>
+ * "_blank" as {@code windowName} causes the resource to always be opened in
+ * a new window or tab (depends on the browser and browser settings).
+ * </p>
+ * <p>
+ * "_top" and "_parent" as {@code windowName} works as specified by the HTML
+ * standard.
+ * </p>
+ * <p>
+ * Any other {@code windowName} will open the resource in a window with that
+ * name, either by opening a new window/tab in the browser or by replacing
+ * the contents of an existing window with that name.
+ * </p>
+ *
+ * @param resource
+ * the resource.
+ * @param windowName
+ * the name of the window.
+ */
+ public void open(Resource resource, String windowName) {
+ synchronized (openList) {
+ if (!openList.contains(resource)) {
+ openList.add(new OpenResource(resource, windowName, -1, -1,
+ BORDER_DEFAULT));
+ }
+ }
+ requestRepaint();
+ }
+
+ /**
+ * Opens the given resource in a window with the given size, border and
+ * name. For more information on the meaning of {@code windowName}, see
+ * {@link #open(Resource, String)}.
+ *
+ * @param resource
+ * the resource.
+ * @param windowName
+ * the name of the window.
+ * @param width
+ * the width of the window in pixels
+ * @param height
+ * the height of the window in pixels
+ * @param border
+ * the border style of the window. See {@link #BORDER_NONE
+ * Window.BORDER_* constants}
+ */
+ public void open(Resource resource, String windowName, int width,
+ int height, int border) {
+ synchronized (openList) {
+ if (!openList.contains(resource)) {
+ openList.add(new OpenResource(resource, windowName, width,
+ height, border));
+ }
+ }
+ requestRepaint();
+ }
+
+ /**
+ * Private class for storing properties related to opening resources.
+ */
+ private class OpenResource implements Serializable {
+
+ /**
+ * The resource to open
+ */
+ private final Resource resource;
+
+ /**
+ * The name of the target window
+ */
+ private final String name;
+
+ /**
+ * The width of the target window
+ */
+ private final int width;
+
+ /**
+ * The height of the target window
+ */
+ private final int height;
+
+ /**
+ * The border style of the target window
+ */
+ private final int border;
+
+ /**
+ * Creates a new open resource.
+ *
+ * @param resource
+ * The resource to open
+ * @param name
+ * The name of the target window
+ * @param width
+ * The width of the target window
+ * @param height
+ * The height of the target window
+ * @param border
+ * The border style of the target window
+ */
+ private OpenResource(Resource resource, String name, int width,
+ int height, int border) {
+ this.resource = resource;
+ this.name = name;
+ this.width = width;
+ this.height = height;
+ this.border = border;
+ }
+
+ /**
+ * Paints the open request. Should be painted inside the window.
+ *
+ * @param target
+ * the paint target
+ * @throws PaintException
+ * if the paint operation fails
+ */
+ private void paintContent(PaintTarget target) throws PaintException {
+ target.startTag("open");
+ target.addAttribute("src", resource);
+ if (name != null && name.length() > 0) {
+ target.addAttribute("name", name);
+ }
+ if (width >= 0) {
+ target.addAttribute("width", width);
+ }
+ if (height >= 0) {
+ target.addAttribute("height", height);
+ }
+ switch (border) {
+ case BORDER_MINIMAL:
+ target.addAttribute("border", "minimal");
+ break;
+ case BORDER_NONE:
+ target.addAttribute("border", "none");
+ break;
+ }
+
+ target.endTag("open");
+ }
+ }
+
+ public void setScrollTop(int scrollTop) {
+ throw new RuntimeException("Not yet implemented");
+ }
+
+ @Override
+ protected ActionManager getActionManager() {
+ if (actionManager == null) {
+ actionManager = new ActionManager(this);
+ }
+ return actionManager;
+ }
+
+ public <T extends Action & com.vaadin.event.Action.Listener> void addAction(
+ T action) {
+ getActionManager().addAction(action);
+ }
+
+ public <T extends Action & com.vaadin.event.Action.Listener> void removeAction(
+ T action) {
+ if (actionManager != null) {
+ actionManager.removeAction(action);
+ }
+ }
+
+ public void addActionHandler(Handler actionHandler) {
+ getActionManager().addActionHandler(actionHandler);
+ }
+
+ public void removeActionHandler(Handler actionHandler) {
+ if (actionManager != null) {
+ actionManager.removeActionHandler(actionHandler);
+ }
+ }
+
+ /**
+ * Should resize operations be lazy, i.e. should there be a delay before
+ * layout sizes are recalculated. Speeds up resize operations in slow UIs
+ * with the penalty of slightly decreased usability.
+ * <p>
+ * Default value: <code>false</code>
+ *
+ * @param resizeLazy
+ * true to use a delay before recalculating sizes, false to
+ * calculate immediately.
+ */
+ public void setResizeLazy(boolean resizeLazy) {
+ this.resizeLazy = resizeLazy;
+ requestRepaint();
+ }
+
+ /**
+ * Checks whether lazy resize is enabled.
+ *
+ * @return <code>true</code> if lazy resize is enabled, <code>false</code>
+ * if lazy resize is not enabled
+ */
+ public boolean isResizeLazy() {
+ return resizeLazy;
+ }
+
+ /**
+ * Add a click listener to the Root. The listener is called whenever the
+ * user clicks inside the Root. Also when the click targets a component
+ * inside the Root, provided the targeted component does not prevent the
+ * click event from propagating.
+ *
+ * Use {@link #removeListener(ClickListener)} to remove the listener.
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addListener(ClickListener listener) {
+ addListener(CLICK_EVENT_ID, ClickEvent.class, listener,
+ ClickListener.clickMethod);
+ }
+
+ /**
+ * Remove a click listener from the Root. The listener should earlier have
+ * been added using {@link #addListener(ClickListener)}.
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeListener(ClickListener listener) {
+ removeListener(CLICK_EVENT_ID, ClickEvent.class, listener);
+ }
+
+ public void addListener(FragmentChangedListener listener) {
+ addListener(FragmentChangedEvent.class, listener,
+ FRAGMENT_CHANGED_METHOD);
+ }
+
+ public void removeListener(FragmentChangedListener listener) {
+ removeListener(FragmentChangedEvent.class, listener,
+ FRAGMENT_CHANGED_METHOD);
+ }
+
+ /**
+ * Sets URI fragment. Optionally fires a {@link FragmentChangedEvent}
+ *
+ * @param newFragment
+ * id of the new fragment
+ * @param fireEvent
+ * true to fire event
+ * @see FragmentChangedEvent
+ * @see FragmentChangedListener
+ */
+ public void setFragment(String newFragment, boolean fireEvents) {
+ if (newFragment == null) {
+ throw new NullPointerException("The fragment may not be null");
+ }
+ if (!newFragment.equals(fragment)) {
+ fragment = newFragment;
+ if (fireEvents) {
+ fireEvent(new FragmentChangedEvent(this, newFragment));
+ }
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Sets URI fragment. This method fires a {@link FragmentChangedEvent}
+ *
+ * @param newFragment
+ * id of the new fragment
+ * @see FragmentChangedEvent
+ * @see FragmentChangedListener
+ */
+ public void setFragment(String newFragment) {
+ setFragment(newFragment, true);
+ }
+
+ /**
+ * Gets currently set URI fragment.
+ * <p>
+ * To listen changes in fragment, hook a {@link FragmentChangedListener}.
+ *
+ * @return the current fragment in browser uri or null if not known
+ */
+ public String getFragment() {
+ return fragment;
+ }
+
+ /**
+ * Adds a new {@link BrowserWindowResizeListener} to this root. The listener
+ * will be notified whenever the browser window within which this root
+ * resides is resized.
+ *
+ * @param resizeListener
+ * the listener to add
+ *
+ * @see BrowserWindowResizeListener#browserWindowResized(BrowserWindowResizeEvent)
+ * @see #setResizeLazy(boolean)
+ */
+ public void addListener(BrowserWindowResizeListener resizeListener) {
+ addListener(BrowserWindowResizeEvent.class, resizeListener,
+ BROWSWER_RESIZE_METHOD);
+ }
+
+ /**
+ * Removes a {@link BrowserWindowResizeListener} from this root. The
+ * listener will no longer be notified when the browser window is resized.
+ *
+ * @param resizeListener
+ * the listener to remove
+ */
+ public void removeListener(BrowserWindowResizeListener resizeListener) {
+ removeListener(BrowserWindowResizeEvent.class, resizeListener,
+ BROWSWER_RESIZE_METHOD);
+ }
+
+ /**
+ * Gets the last known height of the browser window in which this root
+ * resides.
+ *
+ * @return the browser window height in pixels
+ */
+ public int getBrowserWindowHeight() {
+ return browserWindowHeight;
+ }
+
+ /**
+ * Gets the last known width of the browser window in which this root
+ * resides.
+ *
+ * @return the browser window width in pixels
+ */
+ public int getBrowserWindowWidth() {
+ return browserWindowWidth;
+ }
+
+ /**
+ * Notifies the child components and windows that the root is attached to
+ * the application.
+ */
+ @Override
+ public void attach() {
+ super.attach();
+ for (Window w : windows) {
+ w.attach();
+ }
+ }
+
+ /**
+ * Notifies the child components and windows that the root is detached from
+ * the application.
+ */
+ @Override
+ public void detach() {
+ super.detach();
+ for (Window w : windows) {
+ w.detach();
+ }
+ }
+
+}
diff --git a/src/com/vaadin/ui/Select.java b/src/com/vaadin/ui/Select.java
index 0ea331dc40..38785f3ab9 100644
--- a/src/com/vaadin/ui/Select.java
+++ b/src/com/vaadin/ui/Select.java
@@ -23,7 +23,7 @@ import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
-import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
+import com.vaadin.terminal.gwt.client.ui.VFilterSelectPaintable;
/**
* <p>
@@ -44,7 +44,7 @@ import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VFilterSelect.class)
+@ClientWidget(VFilterSelectPaintable.class)
public class Select extends AbstractSelect implements AbstractSelect.Filtering,
FieldEvents.BlurNotifier, FieldEvents.FocusNotifier {
diff --git a/src/com/vaadin/ui/Slider.java b/src/com/vaadin/ui/Slider.java
index 1d67a6b12c..aad1b60f87 100644
--- a/src/com/vaadin/ui/Slider.java
+++ b/src/com/vaadin/ui/Slider.java
@@ -8,7 +8,7 @@ import java.util.Map;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VSlider;
+import com.vaadin.terminal.gwt.client.ui.VSliderPaintable;
/**
* A component for selecting a numerical value within a range.
@@ -46,22 +46,13 @@ import com.vaadin.terminal.gwt.client.ui.VSlider;
*
* @author Vaadin Ltd.
*/
-@ClientWidget(VSlider.class)
-public class Slider extends AbstractField {
+@ClientWidget(VSliderPaintable.class)
+public class Slider extends AbstractField<Double> {
public static final int ORIENTATION_HORIZONTAL = 0;
public static final int ORIENTATION_VERTICAL = 1;
- /**
- * Style constant representing a scrollbar styled slider. Use this with
- * {@link #addStyleName(String)}. Default styling usually represents a
- * common slider found e.g. in Adobe Photoshop. The client side
- * implementation dictates how different styles will look.
- */
- @Deprecated
- public static final String STYLE_SCROLLBAR = "scrollbar";
-
/** Minimum value of slider */
private double min = 0;
@@ -80,35 +71,6 @@ public class Slider extends AbstractField {
private int orientation = ORIENTATION_HORIZONTAL;
/**
- * Slider size in pixels. In horizontal mode, if set to -1, allow 100% width
- * of container. In vertical mode, if set to -1, default height is
- * determined by the client-side implementation.
- *
- * @deprecated
- */
- @Deprecated
- private int size = -1;
-
- /**
- * Handle (draggable control element) size in percents relative to base
- * size. Must be a value between 1-99. Other values are converted to nearest
- * bound. A negative value sets the width to auto (client-side
- * implementation calculates).
- *
- * @deprecated The size is dictated by the current theme.
- */
- @Deprecated
- private int handleSize = -1;
-
- /**
- * Show arrows that can be pressed to slide the handle in some increments
- * (client-side implementation decides the increment, usually somewhere
- * between 5-10% of slide range).
- */
- @Deprecated
- private final boolean arrows = false;
-
- /**
* Default slider constructor. Sets all values to defaults and the slide
* handle at minimum value.
*
@@ -198,17 +160,8 @@ public class Slider extends AbstractField {
*/
public void setMax(double max) {
this.max = max;
- try {
- if ((new Double(getValue().toString())).doubleValue() > max) {
- super.setValue(new Double(max));
- }
- } catch (final ClassCastException e) {
- // FIXME: Handle exception
- /*
- * Where does ClassCastException come from? Can't see any casts
- * above
- */
- super.setValue(new Double(max));
+ if (getValue() > max) {
+ setValue(max);
}
requestRepaint();
}
@@ -231,17 +184,8 @@ public class Slider extends AbstractField {
*/
public void setMin(double min) {
this.min = min;
- try {
- if ((new Double(getValue().toString())).doubleValue() < min) {
- super.setValue(new Double(min));
- }
- } catch (final ClassCastException e) {
- // FIXME: Handle exception
- /*
- * Where does ClassCastException come from? Can't see any casts
- * above
- */
- super.setValue(new Double(min));
+ if (getValue() < min) {
+ setValue(min);
}
requestRepaint();
}
@@ -303,8 +247,8 @@ public class Slider extends AbstractField {
* If the given value is not inside the range of the slider.
* @see #setMin(double) {@link #setMax(double)}
*/
- public void setValue(Double value, boolean repaintIsNotNeeded)
- throws ValueOutOfBoundsException {
+ @Override
+ protected void setValue(Double value, boolean repaintIsNotNeeded) {
final double v = value.doubleValue();
double newValue;
if (resolution > 0) {
@@ -320,97 +264,19 @@ public class Slider extends AbstractField {
throw new ValueOutOfBoundsException(value);
}
}
- super.setValue(new Double(newValue), repaintIsNotNeeded);
- }
-
- /**
- * Sets the value of the slider.
- *
- * @param value
- * The new value of the slider.
- * @throws ValueOutOfBoundsException
- * If the given value is not inside the range of the slider.
- * @see #setMin(double) {@link #setMax(double)}
- */
- public void setValue(Double value) throws ValueOutOfBoundsException {
- setValue(value, false);
- }
-
- /**
- * Sets the value of the slider.
- *
- * @param value
- * The new value of the slider.
- * @throws ValueOutOfBoundsException
- * If the given value is not inside the range of the slider.
- * @see #setMin(double) {@link #setMax(double)}
- */
- public void setValue(double value) throws ValueOutOfBoundsException {
- setValue(new Double(value), false);
+ super.setValue(newValue, repaintIsNotNeeded);
}
- /**
- * Get the current slider size.
- *
- * @return size in pixels or -1 for auto sizing.
- * @deprecated use standard getWidth/getHeight instead
- */
- @Deprecated
- public int getSize() {
- return size;
- }
-
- /**
- * Set the size for this slider.
- *
- * @param size
- * in pixels, or -1 auto sizing.
- * @deprecated use standard setWidth/setHeight instead
- */
- @Deprecated
- public void setSize(int size) {
- this.size = size;
- switch (orientation) {
- case ORIENTATION_HORIZONTAL:
- setWidth(size, UNITS_PIXELS);
- break;
- default:
- setHeight(size, UNITS_PIXELS);
- break;
+ @Override
+ public void setValue(Object newFieldValue)
+ throws com.vaadin.data.Property.ReadOnlyException {
+ if (newFieldValue != null && newFieldValue instanceof Number
+ && !(newFieldValue instanceof Double)) {
+ // Support setting all types of Numbers
+ newFieldValue = ((Number) newFieldValue).doubleValue();
}
- requestRepaint();
- }
-
- /**
- * Get the handle size of this slider.
- *
- * @return handle size in percentages.
- * @deprecated The size is dictated by the current theme.
- */
- @Deprecated
- public int getHandleSize() {
- return handleSize;
- }
- /**
- * Set the handle size of this slider.
- *
- * @param handleSize
- * in percentages relative to slider base size.
- * @deprecated The size is dictated by the current theme.
- */
- @Deprecated
- public void setHandleSize(int handleSize) {
- if (handleSize < 0) {
- this.handleSize = -1;
- } else if (handleSize > 99) {
- this.handleSize = 99;
- } else if (handleSize < 1) {
- this.handleSize = 1;
- } else {
- this.handleSize = handleSize;
- }
- requestRepaint();
+ super.setValue(newFieldValue);
}
@Override
@@ -426,30 +292,15 @@ public class Slider extends AbstractField {
target.addAttribute("resolution", resolution);
if (resolution > 0) {
- target.addVariable(this, "value",
- ((Double) getValue()).doubleValue());
+ target.addVariable(this, "value", getValue().doubleValue());
} else {
- target.addVariable(this, "value", ((Double) getValue()).intValue());
+ target.addVariable(this, "value", getValue().intValue());
}
if (orientation == ORIENTATION_VERTICAL) {
target.addAttribute("vertical", true);
}
- if (arrows) {
- target.addAttribute("arrows", true);
- }
-
- if (size > -1) {
- target.addAttribute("size", size);
- }
-
- if (min != max && min < max) {
- target.addAttribute("hsize", handleSize);
- } else {
- target.addAttribute("hsize", 100);
- }
-
}
/**
@@ -491,7 +342,7 @@ public class Slider extends AbstractField {
* @author Vaadin Ltd.
*
*/
- public class ValueOutOfBoundsException extends Exception {
+ public class ValueOutOfBoundsException extends RuntimeException {
private final Double value;
@@ -517,7 +368,7 @@ public class Slider extends AbstractField {
}
@Override
- public Class getType() {
+ public Class<Double> getType() {
return Double.class;
}
diff --git a/src/com/vaadin/ui/SplitPanel.java b/src/com/vaadin/ui/SplitPanel.java
deleted file mode 100644
index bae1bf7ce0..0000000000
--- a/src/com/vaadin/ui/SplitPanel.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.ui;
-
-import com.vaadin.terminal.PaintException;
-import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal;
-import com.vaadin.ui.ClientWidget.LoadStyle;
-
-/**
- * SplitPanel.
- *
- * <code>SplitPanel</code> is a component container, that can contain two
- * components (possibly containers) which are split by divider element.
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 5.0
- * @deprecated in 6.5. Use {@link HorizontalSplitPanel} or
- * {@link VerticalSplitPanel} instead.
- */
-@Deprecated
-@ClientWidget(value = VSplitPanelHorizontal.class, loadStyle = LoadStyle.EAGER)
-public class SplitPanel extends AbstractSplitPanel {
-
- /* Predefined orientations */
-
- /**
- * Components are to be laid out vertically.
- */
- public static final int ORIENTATION_VERTICAL = 0;
-
- /**
- * Components are to be laid out horizontally.
- */
- public static final int ORIENTATION_HORIZONTAL = 1;
-
- /**
- * Orientation of the layout.
- */
- private int orientation;
-
- /**
- * Creates a new split panel. The orientation of the panels is
- * <code>ORIENTATION_VERTICAL</code>.
- */
- public SplitPanel() {
- super();
- orientation = ORIENTATION_VERTICAL;
- setSizeFull();
- }
-
- /**
- * Create a new split panels. The orientation of the panel is given as
- * parameters.
- *
- * @param orientation
- * the Orientation of the layout.
- */
- public SplitPanel(int orientation) {
- this();
- setOrientation(orientation);
- }
-
- /**
- * Paints the content of this component.
- *
- * @param target
- * the Paint Event.
- * @throws PaintException
- * if the paint operation failed.
- */
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- super.paintContent(target);
-
- if (orientation == ORIENTATION_VERTICAL) {
- target.addAttribute("vertical", true);
- }
-
- }
-
- /**
- * Gets the orientation of the split panel.
- *
- * @return the Value of property orientation.
- *
- */
- public int getOrientation() {
- return orientation;
- }
-
- /**
- * Sets the orientation of the split panel.
- *
- * @param orientation
- * the New value of property orientation.
- */
- public void setOrientation(int orientation) {
-
- // Checks the validity of the argument
- if (orientation < ORIENTATION_VERTICAL
- || orientation > ORIENTATION_HORIZONTAL) {
- throw new IllegalArgumentException();
- }
-
- this.orientation = orientation;
- requestRepaint();
- }
-
-}
diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java
index a13c336943..e256c51cfd 100644
--- a/src/com/vaadin/ui/TabSheet.java
+++ b/src/com/vaadin/ui/TabSheet.java
@@ -20,6 +20,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.ui.VTabsheet;
+import com.vaadin.terminal.gwt.client.ui.VTabsheetPaintable;
import com.vaadin.terminal.gwt.server.CommunicationManager;
import com.vaadin.ui.themes.Reindeer;
import com.vaadin.ui.themes.Runo;
@@ -53,8 +54,7 @@ import com.vaadin.ui.themes.Runo;
* @VERSION@
* @since 3.0
*/
-@SuppressWarnings("serial")
-@ClientWidget(VTabsheet.class)
+@ClientWidget(VTabsheetPaintable.class)
public class TabSheet extends AbstractComponentContainer {
/**
diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java
index 199a6805f6..003ef6978c 100644
--- a/src/com/vaadin/ui/Table.java
+++ b/src/com/vaadin/ui/Table.java
@@ -20,11 +20,13 @@ import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
+import com.vaadin.Application;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.ContainerOrderedWrapper;
import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.data.util.converter.Converter;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.DataBoundTransferable;
@@ -45,6 +47,7 @@ import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.VScrollTable;
+import com.vaadin.terminal.gwt.client.ui.VScrollTablePaintable;
import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
/**
@@ -70,8 +73,8 @@ import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
* @VERSION@
* @since 3.0
*/
-@SuppressWarnings({ "serial", "deprecation" })
-@ClientWidget(VScrollTable.class)
+@SuppressWarnings({ "deprecation" })
+@ClientWidget(VScrollTablePaintable.class)
public class Table extends AbstractSelect implements Action.Container,
Container.Ordered, Container.Sortable, ItemClickSource,
ItemClickNotifier, DragSource, DropTarget {
@@ -113,91 +116,215 @@ public class Table extends AbstractSelect implements Action.Container,
protected static final int CELL_FIRSTCOL = 5;
+ public enum Align {
+ /**
+ * Left column alignment. <b>This is the default behaviour. </b>
+ */
+ LEFT("b"),
+
+ /**
+ * Center column alignment.
+ */
+ CENTER("c"),
+
+ /**
+ * Right column alignment.
+ */
+ RIGHT("e");
+
+ private String alignment;
+
+ private Align(String alignment) {
+ this.alignment = alignment;
+ }
+
+ @Override
+ public String toString() {
+ return alignment;
+ }
+
+ public Align convertStringToAlign(String string) {
+ if (string == null) {
+ return null;
+ }
+ if (string.equals("b")) {
+ return Align.LEFT;
+ } else if (string.equals("c")) {
+ return Align.CENTER;
+ } else if (string.equals("e")) {
+ return Align.RIGHT;
+ } else {
+ return null;
+ }
+ }
+ }
+
/**
- * Left column alignment. <b>This is the default behaviour. </b>
+ * @deprecated from 7.0, use {@link Align#LEFT} instead
*/
- public static final String ALIGN_LEFT = "b";
+ @Deprecated
+ public static final Align ALIGN_LEFT = Align.LEFT;
/**
- * Center column alignment.
+ * @deprecated from 7.0, use {@link Align#CENTER} instead
*/
- public static final String ALIGN_CENTER = "c";
+ @Deprecated
+ public static final Align ALIGN_CENTER = Align.CENTER;
/**
- * Right column alignment.
+ * @deprecated from 7.0, use {@link Align#RIGHT} instead
*/
- public static final String ALIGN_RIGHT = "e";
+ @Deprecated
+ public static final Align ALIGN_RIGHT = Align.RIGHT;
+
+ public enum ColumnHeaderMode {
+ /**
+ * Column headers are hidden.
+ */
+ HIDDEN,
+ /**
+ * Property ID:s are used as column headers.
+ */
+ ID,
+ /**
+ * Column headers are explicitly specified with
+ * {@link #setColumnHeaders(String[])}.
+ */
+ EXPLICIT,
+ /**
+ * Column headers are explicitly specified with
+ * {@link #setColumnHeaders(String[])}. If a header is not specified for
+ * a given property, its property id is used instead.
+ * <p>
+ * <b>This is the default behavior. </b>
+ */
+ EXPLICIT_DEFAULTS_ID
+ }
/**
- * Column header mode: Column headers are hidden.
+ * @deprecated from 7.0, use {@link ColumnHeaderMode#HIDDEN} instead
*/
- public static final int COLUMN_HEADER_MODE_HIDDEN = -1;
+ @Deprecated
+ public static final ColumnHeaderMode COLUMN_HEADER_MODE_HIDDEN = ColumnHeaderMode.HIDDEN;
/**
- * Column header mode: Property ID:s are used as column headers.
+ * @deprecated from 7.0, use {@link ColumnHeaderMode#ID} instead
*/
- public static final int COLUMN_HEADER_MODE_ID = 0;
+ @Deprecated
+ public static final ColumnHeaderMode COLUMN_HEADER_MODE_ID = ColumnHeaderMode.ID;
/**
- * Column header mode: Column headers are explicitly specified with
- * {@link #setColumnHeaders(String[])}.
+ * @deprecated from 7.0, use {@link ColumnHeaderMode#EXPLICIT} instead
*/
- public static final int COLUMN_HEADER_MODE_EXPLICIT = 1;
+ @Deprecated
+ public static final ColumnHeaderMode COLUMN_HEADER_MODE_EXPLICIT = ColumnHeaderMode.EXPLICIT;
/**
- * Column header mode: Column headers are explicitly specified with
- * {@link #setColumnHeaders(String[])}. If a header is not specified for a
- * given property, its property id is used instead.
- * <p>
- * <b>This is the default behavior. </b>
+ * @deprecated from 7.0, use {@link ColumnHeaderMode#EXPLICIT_DEFAULTS_ID}
+ * instead
*/
- public static final int COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID = 2;
+ @Deprecated
+ public static final ColumnHeaderMode COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID = ColumnHeaderMode.EXPLICIT_DEFAULTS_ID;
+
+ public enum RowHeaderMode {
+ /**
+ * Row caption mode: The row headers are hidden. <b>This is the default
+ * mode. </b>
+ */
+ HIDDEN(null),
+ /**
+ * Row caption mode: Items Id-objects toString is used as row caption.
+ */
+ ID(ItemCaptionMode.ID),
+ /**
+ * Row caption mode: Item-objects toString is used as row caption.
+ */
+ ITEM(ItemCaptionMode.ITEM),
+ /**
+ * Row caption mode: Index of the item is used as item caption. The
+ * index mode can only be used with the containers implementing the
+ * {@link com.vaadin.data.Container.Indexed} interface.
+ */
+ INDEX(ItemCaptionMode.INDEX),
+ /**
+ * Row caption mode: Item captions are explicitly specified, but if the
+ * caption is missing, the item id objects <code>toString()</code> is
+ * used instead.
+ */
+ EXPLICIT_DEFAULTS_ID(ItemCaptionMode.EXPLICIT_DEFAULTS_ID),
+ /**
+ * Row caption mode: Item captions are explicitly specified.
+ */
+ EXPLICIT(ItemCaptionMode.EXPLICIT),
+ /**
+ * Row caption mode: Only icons are shown, the captions are hidden.
+ */
+ ICON_ONLY(ItemCaptionMode.ICON_ONLY),
+ /**
+ * Row caption mode: Item captions are read from property specified with
+ * {@link #setItemCaptionPropertyId(Object)}.
+ */
+ PROPERTY(ItemCaptionMode.PROPERTY);
+
+ ItemCaptionMode mode;
+
+ private RowHeaderMode(ItemCaptionMode mode) {
+ this.mode = mode;
+ }
+
+ public ItemCaptionMode getItemCaptionMode() {
+ return mode;
+ }
+ }
/**
- * Row caption mode: The row headers are hidden. <b>This is the default
- * mode. </b>
+ * @deprecated from 7.0, use {@link RowHeaderMode#HIDDEN} instead
*/
- public static final int ROW_HEADER_MODE_HIDDEN = -1;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_HIDDEN = RowHeaderMode.HIDDEN;
/**
- * Row caption mode: Items Id-objects toString is used as row caption.
+ * @deprecated from 7.0, use {@link RowHeaderMode#ID} instead
*/
- public static final int ROW_HEADER_MODE_ID = AbstractSelect.ITEM_CAPTION_MODE_ID;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_ID = RowHeaderMode.ID;
/**
- * Row caption mode: Item-objects toString is used as row caption.
+ * @deprecated from 7.0, use {@link RowHeaderMode#ITEM} instead
*/
- public static final int ROW_HEADER_MODE_ITEM = AbstractSelect.ITEM_CAPTION_MODE_ITEM;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_ITEM = RowHeaderMode.ITEM;
/**
- * Row caption mode: Index of the item is used as item caption. The index
- * mode can only be used with the containers implementing Container.Indexed
- * interface.
+ * @deprecated from 7.0, use {@link RowHeaderMode#INDEX} instead
*/
- public static final int ROW_HEADER_MODE_INDEX = AbstractSelect.ITEM_CAPTION_MODE_INDEX;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_INDEX = RowHeaderMode.INDEX;
/**
- * Row caption mode: Item captions are explicitly specified.
+ * @deprecated from 7.0, use {@link RowHeaderMode#EXPLICIT_DEFAULTS_ID}
+ * instead
*/
- public static final int ROW_HEADER_MODE_EXPLICIT = AbstractSelect.ITEM_CAPTION_MODE_EXPLICIT;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID = RowHeaderMode.EXPLICIT_DEFAULTS_ID;
/**
- * Row caption mode: Item captions are read from property specified with
- * {@link #setItemCaptionPropertyId(Object)}.
+ * @deprecated from 7.0, use {@link RowHeaderMode#EXPLICIT} instead
*/
- public static final int ROW_HEADER_MODE_PROPERTY = AbstractSelect.ITEM_CAPTION_MODE_PROPERTY;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_EXPLICIT = RowHeaderMode.EXPLICIT;
/**
- * Row caption mode: Only icons are shown, the captions are hidden.
+ * @deprecated from 7.0, use {@link RowHeaderMode#ICON_ONLY} instead
*/
- public static final int ROW_HEADER_MODE_ICON_ONLY = AbstractSelect.ITEM_CAPTION_MODE_ICON_ONLY;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_ICON_ONLY = RowHeaderMode.ICON_ONLY;
/**
- * Row caption mode: Item captions are explicitly specified, but if the
- * caption is missing, the item id objects <code>toString()</code> is used
- * instead.
+ * @deprecated from 7.0, use {@link RowHeaderMode#PROPERTY} instead
*/
- public static final int ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID = AbstractSelect.ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID;
+ @Deprecated
+ public static final RowHeaderMode ROW_HEADER_MODE_PROPERTY = RowHeaderMode.PROPERTY;
/**
* The default rate that table caches rows for smooth scrolling.
@@ -252,7 +379,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Holds alignments for visible columns (by propertyId).
*/
- private HashMap<Object, String> columnAlignments = new HashMap<Object, String>();
+ private HashMap<Object, Align> columnAlignments = new HashMap<Object, Align>();
/**
* Holds column widths in pixels (Integer) or expand ratios (Float) for
@@ -288,17 +415,17 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Holds value of property columnHeaderMode.
*/
- private int columnHeaderMode = COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID;
+ private ColumnHeaderMode columnHeaderMode = ColumnHeaderMode.EXPLICIT_DEFAULTS_ID;
/**
- * Should the Table footer be visible?
+ * Holds value of property rowHeaderMode.
*/
- private boolean columnFootersVisible = false;
+ private RowHeaderMode rowHeaderMode = RowHeaderMode.EXPLICIT_DEFAULTS_ID;
/**
- * True iff the row captions are hidden.
+ * Should the Table footer be visible?
*/
- private boolean rowCaptionsAreHidden = true;
+ private boolean columnFootersVisible = false;
/**
* Page contents buffer used in buffered mode.
@@ -309,7 +436,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Set of properties listened - the list is kept to release the listeners
* later.
*/
- private HashSet<Property> listenedProperties = null;
+ private HashSet<Property<?>> listenedProperties = null;
/**
* Set of visible components - the is used for needsRepaint calculation.
@@ -404,10 +531,12 @@ public class Table extends AbstractSelect implements Action.Container,
private RowGenerator rowGenerator = null;
- private final Map<Field, Property> associatedProperties = new HashMap<Field, Property>();
+ private final Map<Field<?>, Property<?>> associatedProperties = new HashMap<Field<?>, Property<?>>();
private boolean painted = false;
+ private HashMap<Object, Converter<String, Object>> propertyValueConverters = new HashMap<Object, Converter<String, Object>>();
+
/* Table constructors */
/**
@@ -508,7 +637,7 @@ public class Table extends AbstractSelect implements Action.Container,
final Object col = i.next();
if (!newVC.contains(col)) {
setColumnHeader(col, null);
- setColumnAlignment(col, null);
+ setColumnAlignment(col, (Align) null);
setColumnIcon(col, null);
}
}
@@ -652,21 +781,21 @@ public class Table extends AbstractSelect implements Action.Container,
* {@link #getVisibleColumns()}. The possible values for the alignments
* include:
* <ul>
- * <li>{@link #ALIGN_LEFT}: Left alignment</li>
- * <li>{@link #ALIGN_CENTER}: Centered</li>
- * <li>{@link #ALIGN_RIGHT}: Right alignment</li>
+ * <li>{@link Align#LEFT}: Left alignment</li>
+ * <li>{@link Align#CENTER}: Centered</li>
+ * <li>{@link Align#RIGHT}: Right alignment</li>
* </ul>
- * The alignments default to {@link #ALIGN_LEFT}: any null values are
+ * The alignments default to {@link Align#LEFT}: any null values are
* rendered as align lefts.
* </p>
*
* @return the Column alignments array.
*/
- public String[] getColumnAlignments() {
+ public Align[] getColumnAlignments() {
if (columnAlignments == null) {
return null;
}
- final String[] alignments = new String[visibleColumns.size()];
+ final Align[] alignments = new Align[visibleColumns.size()];
int i = 0;
for (final Iterator<Object> it = visibleColumns.iterator(); it
.hasNext(); i++) {
@@ -680,39 +809,29 @@ public class Table extends AbstractSelect implements Action.Container,
* Sets the column alignments.
*
* <p>
- * The items in the array must match the properties identified by
- * {@link #getVisibleColumns()}. The possible values for the alignments
- * include:
+ * The amount of items in the array must match the amount of properties
+ * identified by {@link #getVisibleColumns()}. The possible values for the
+ * alignments include:
* <ul>
- * <li>{@link #ALIGN_LEFT}: Left alignment</li>
- * <li>{@link #ALIGN_CENTER}: Centered</li>
- * <li>{@link #ALIGN_RIGHT}: Right alignment</li>
+ * <li>{@link Align#LEFT}: Left alignment</li>
+ * <li>{@link Align#CENTER}: Centered</li>
+ * <li>{@link Align#RIGHT}: Right alignment</li>
* </ul>
- * The alignments default to {@link #ALIGN_LEFT}
+ * The alignments default to {@link Align#LEFT}
* </p>
*
* @param columnAlignments
* the Column alignments array.
*/
- public void setColumnAlignments(String[] columnAlignments) {
+ public void setColumnAlignments(Align... columnAlignments) {
if (columnAlignments.length != visibleColumns.size()) {
throw new IllegalArgumentException(
"The length of the alignments array must match the number of visible columns");
}
- // Checks all alignments
- for (int i = 0; i < columnAlignments.length; i++) {
- final String a = columnAlignments[i];
- if (a != null && !a.equals(ALIGN_LEFT) && !a.equals(ALIGN_CENTER)
- && !a.equals(ALIGN_RIGHT)) {
- throw new IllegalArgumentException("Column " + i
- + " aligment '" + a + "' is invalid");
- }
- }
-
// Resets the alignments
- final HashMap<Object, String> newCA = new HashMap<Object, String>();
+ final HashMap<Object, Align> newCA = new HashMap<Object, Align>();
int i = 0;
for (final Iterator<Object> it = visibleColumns.iterator(); it
.hasNext() && i < columnAlignments.length; i++) {
@@ -1030,13 +1149,13 @@ public class Table extends AbstractSelect implements Action.Container,
* @return the header for the specified column if it has one.
*/
public String getColumnHeader(Object propertyId) {
- if (getColumnHeaderMode() == COLUMN_HEADER_MODE_HIDDEN) {
+ if (getColumnHeaderMode() == ColumnHeaderMode.HIDDEN) {
return null;
}
String header = columnHeaders.get(propertyId);
- if ((header == null && getColumnHeaderMode() == COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID)
- || getColumnHeaderMode() == COLUMN_HEADER_MODE_ID) {
+ if ((header == null && getColumnHeaderMode() == ColumnHeaderMode.EXPLICIT_DEFAULTS_ID)
+ || getColumnHeaderMode() == ColumnHeaderMode.ID) {
header = propertyId.toString();
}
@@ -1069,9 +1188,9 @@ public class Table extends AbstractSelect implements Action.Container,
* the propertyID identifying the column.
* @return the specified column's alignment if it as one; null otherwise.
*/
- public String getColumnAlignment(Object propertyId) {
- final String a = columnAlignments.get(propertyId);
- return a == null ? ALIGN_LEFT : a;
+ public Align getColumnAlignment(Object propertyId) {
+ final Align a = columnAlignments.get(propertyId);
+ return a == null ? Align.LEFT : a;
}
/**
@@ -1079,8 +1198,8 @@ public class Table extends AbstractSelect implements Action.Container,
*
* <p>
* Throws IllegalArgumentException if the alignment is not one of the
- * following: {@link #ALIGN_LEFT}, {@link #ALIGN_CENTER} or
- * {@link #ALIGN_RIGHT}
+ * following: {@link Align#LEFT}, {@link Align#CENTER} or
+ * {@link Align#RIGHT}
* </p>
*
* @param propertyId
@@ -1088,17 +1207,8 @@ public class Table extends AbstractSelect implements Action.Container,
* @param alignment
* the desired alignment.
*/
- public void setColumnAlignment(Object propertyId, String alignment) {
-
- // Checks for valid alignments
- if (alignment != null && !alignment.equals(ALIGN_LEFT)
- && !alignment.equals(ALIGN_CENTER)
- && !alignment.equals(ALIGN_RIGHT)) {
- throw new IllegalArgumentException("Column alignment '" + alignment
- + "' is not supported.");
- }
-
- if (alignment == null || alignment.equals(ALIGN_LEFT)) {
+ public void setColumnAlignment(Object propertyId, Align alignment) {
+ if (alignment == null || alignment == Align.LEFT) {
columnAlignments.remove(propertyId);
} else {
columnAlignments.put(propertyId, alignment);
@@ -1393,7 +1503,7 @@ public class Table extends AbstractSelect implements Action.Container,
*
* @return the Value of property columnHeaderMode.
*/
- public int getColumnHeaderMode() {
+ public ColumnHeaderMode getColumnHeaderMode() {
return columnHeaderMode;
}
@@ -1403,10 +1513,12 @@ public class Table extends AbstractSelect implements Action.Container,
* @param columnHeaderMode
* the New value of property columnHeaderMode.
*/
- public void setColumnHeaderMode(int columnHeaderMode) {
- if (columnHeaderMode != this.columnHeaderMode
- && columnHeaderMode >= COLUMN_HEADER_MODE_HIDDEN
- && columnHeaderMode <= COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) {
+ public void setColumnHeaderMode(ColumnHeaderMode columnHeaderMode) {
+ if (columnHeaderMode == null) {
+ throw new IllegalArgumentException(
+ "Column header mode can not be null");
+ }
+ if (columnHeaderMode != this.columnHeaderMode) {
this.columnHeaderMode = columnHeaderMode;
requestRepaint();
}
@@ -1718,13 +1830,13 @@ public class Table extends AbstractSelect implements Action.Container,
final Object[] colids = getVisibleColumns();
final int cols = colids.length;
- HashSet<Property> oldListenedProperties = listenedProperties;
+ HashSet<Property<?>> oldListenedProperties = listenedProperties;
HashSet<Component> oldVisibleComponents = visibleComponents;
if (replaceListeners) {
// initialize the listener collections, this should only be done if
// the entire cache is refreshed (through refreshRenderedCells)
- listenedProperties = new HashSet<Property>();
+ listenedProperties = new HashSet<Property<?>>();
visibleComponents = new HashSet<Component>();
}
@@ -1746,7 +1858,7 @@ public class Table extends AbstractSelect implements Action.Container,
}
}
- final int headmode = getRowHeaderMode();
+ final RowHeaderMode headmode = getRowHeaderMode();
final boolean[] iscomponent = new boolean[cols];
for (int i = 0; i < cols; i++) {
iscomponent[i] = columnGenerators.containsKey(colids[i])
@@ -1767,7 +1879,7 @@ public class Table extends AbstractSelect implements Action.Container,
cells[CELL_KEY][i] = itemIdMapper.key(id);
if (headmode != ROW_HEADER_MODE_HIDDEN) {
switch (headmode) {
- case ROW_HEADER_MODE_INDEX:
+ case INDEX:
cells[CELL_HEADER][i] = String.valueOf(i + firstIndex + 1);
break;
default:
@@ -1784,7 +1896,7 @@ public class Table extends AbstractSelect implements Action.Container,
if (isColumnCollapsed(colids[j])) {
continue;
}
- Property p = null;
+ Property<?> p = null;
Object value = "";
boolean isGeneratedRow = generatedRow != null;
boolean isGeneratedColumn = columnGenerators
@@ -1904,8 +2016,8 @@ public class Table extends AbstractSelect implements Action.Container,
visibleComponents.add(component);
}
- private void listenProperty(Property p,
- HashSet<Property> oldListenedProperties) {
+ private void listenProperty(Property<?> p,
+ HashSet<Property<?>> oldListenedProperties) {
if (p instanceof Property.ValueChangeNotifier) {
if (oldListenedProperties == null
|| !oldListenedProperties.contains(p)) {
@@ -1945,7 +2057,7 @@ public class Table extends AbstractSelect implements Action.Container,
visibleComponents.remove(cellVal);
unregisterComponent((Component) cellVal);
} else {
- Property p = getContainerProperty(
+ Property<?> p = getContainerProperty(
pageBuffer[CELL_ITEMID][i + ix], colids[c]);
if (p instanceof ValueChangeNotifier
&& listenedProperties.contains(p)) {
@@ -1970,7 +2082,7 @@ public class Table extends AbstractSelect implements Action.Container,
* set of components that where attached in last render
*/
private void unregisterPropertiesAndComponents(
- HashSet<Property> oldListenedProperties,
+ HashSet<Property<?>> oldListenedProperties,
HashSet<Component> oldVisibleComponents) {
if (oldVisibleComponents != null) {
for (final Iterator<Component> i = oldVisibleComponents.iterator(); i
@@ -1983,8 +2095,8 @@ public class Table extends AbstractSelect implements Action.Container,
}
if (oldListenedProperties != null) {
- for (final Iterator<Property> i = oldListenedProperties.iterator(); i
- .hasNext();) {
+ for (final Iterator<Property<?>> i = oldListenedProperties
+ .iterator(); i.hasNext();) {
Property.ValueChangeNotifier o = (ValueChangeNotifier) i.next();
if (!listenedProperties.contains(o)) {
o.removeListener(this);
@@ -2017,8 +2129,8 @@ public class Table extends AbstractSelect implements Action.Container,
* fields in memory.
*/
if (component instanceof Field) {
- Field field = (Field) component;
- Property associatedProperty = associatedProperties
+ Field<?> field = (Field<?>) component;
+ Property<?> associatedProperty = associatedProperties
.remove(component);
if (associatedProperty != null
&& field.getPropertyDataSource() == associatedProperty) {
@@ -2066,17 +2178,17 @@ public class Table extends AbstractSelect implements Action.Container,
* @param mode
* the One of the modes listed above.
*/
- public void setRowHeaderMode(int mode) {
- if (ROW_HEADER_MODE_HIDDEN == mode) {
- rowCaptionsAreHidden = true;
- } else {
- rowCaptionsAreHidden = false;
- setItemCaptionMode(mode);
+ public void setRowHeaderMode(RowHeaderMode mode) {
+ if (mode != null) {
+ rowHeaderMode = mode;
+ if (mode != RowHeaderMode.HIDDEN) {
+ setItemCaptionMode(mode.getItemCaptionMode());
+ }
+ // Assures the visual refresh. No need to reset the page buffer
+ // before
+ // as the content has not changed, only the alignments.
+ refreshRenderedCells();
}
-
- // Assures the visual refresh. No need to reset the page buffer before
- // as the content has not changed, only the alignments.
- refreshRenderedCells();
}
/**
@@ -2085,9 +2197,8 @@ public class Table extends AbstractSelect implements Action.Container,
* @return the Row header mode.
* @see #setRowHeaderMode(int)
*/
- public int getRowHeaderMode() {
- return rowCaptionsAreHidden ? ROW_HEADER_MODE_HIDDEN
- : getItemCaptionMode();
+ public RowHeaderMode getRowHeaderMode() {
+ return rowHeaderMode;
}
/**
@@ -2924,7 +3035,7 @@ public class Table extends AbstractSelect implements Action.Container,
}
private boolean areColumnHeadersEnabled() {
- return getColumnHeaderMode() != COLUMN_HEADER_MODE_HIDDEN;
+ return getColumnHeaderMode() != ColumnHeaderMode.HIDDEN;
}
private void paintVisibleColumns(PaintTarget target) throws PaintException {
@@ -2955,8 +3066,9 @@ public class Table extends AbstractSelect implements Action.Container,
target.addAttribute("sortable", true);
}
}
- if (!ALIGN_LEFT.equals(getColumnAlignment(colId))) {
- target.addAttribute("align", getColumnAlignment(colId));
+ if (!Align.LEFT.equals(getColumnAlignment(colId))) {
+ target.addAttribute("align", getColumnAlignment(colId)
+ .toString());
}
paintColumnWidth(target, colId);
target.endTag("column");
@@ -3402,8 +3514,8 @@ public class Table extends AbstractSelect implements Action.Container,
protected Object getPropertyValue(Object rowId, Object colId,
Property property) {
if (isEditable() && fieldFactory != null) {
- final Field f = fieldFactory.createField(getContainerDataSource(),
- rowId, colId, this);
+ final Field<?> f = fieldFactory.createField(
+ getContainerDataSource(), rowId, colId, this);
if (f != null) {
// Remember that we have made this association so we can remove
// it when the component is removed
@@ -3457,11 +3569,27 @@ public class Table extends AbstractSelect implements Action.Container,
* @since 3.1
*/
protected String formatPropertyValue(Object rowId, Object colId,
- Property property) {
+ Property<?> property) {
if (property == null) {
return "";
}
- return property.toString();
+ Converter<String, Object> converter = null;
+
+ if (hasConverter(colId)) {
+ converter = getConverter(colId);
+ } else {
+ Application app = Application.getCurrentApplication();
+ if (app != null) {
+ converter = (Converter<String, Object>) app
+ .getConverterFactory().createConverter(String.class,
+ property.getType());
+ }
+ }
+ Object value = property.getValue();
+ if (converter != null) {
+ return converter.convertToPresentation(value, getLocale());
+ }
+ return (null != value) ? value.toString() : "";
}
/* Action container */
@@ -3704,7 +3832,7 @@ public class Table extends AbstractSelect implements Action.Container,
*/
public boolean addContainerProperty(Object propertyId, Class<?> type,
Object defaultValue, String columnHeader, Resource columnIcon,
- String columnAlignment) throws UnsupportedOperationException {
+ Align columnAlignment) throws UnsupportedOperationException {
if (!this.addContainerProperty(propertyId, type, defaultValue)) {
return false;
}
@@ -4034,44 +4162,6 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
- * Gets the FieldFactory that is used to create editor for table cells.
- *
- * The FieldFactory is only used if the Table is editable.
- *
- * @return FieldFactory used to create the Field instances.
- * @see #isEditable
- * @deprecated use {@link #getTableFieldFactory()} instead
- */
- @Deprecated
- public FieldFactory getFieldFactory() {
- if (fieldFactory instanceof FieldFactory) {
- return (FieldFactory) fieldFactory;
-
- }
- return null;
- }
-
- /**
- * Sets the FieldFactory that is used to create editor for table cells.
- *
- * The FieldFactory is only used if the Table is editable. By default the
- * BaseFieldFactory is used.
- *
- * @param fieldFactory
- * the field factory to set.
- * @see #isEditable
- * @see BaseFieldFactory
- * @deprecated use {@link #setTableFieldFactory(TableFieldFactory)} instead
- */
- @Deprecated
- public void setFieldFactory(FieldFactory fieldFactory) {
- this.fieldFactory = fieldFactory;
-
- // Assure visual refresh
- refreshRowCache();
- }
-
- /**
* Is table editable.
*
* If table is editable a editor of type Field is created for each table
@@ -5152,6 +5242,62 @@ public class Table extends AbstractSelect implements Action.Container,
return rowGenerator;
}
+ /**
+ * Sets a converter for a property id.
+ * <p>
+ * The converter is used to format the the data for the given property id
+ * before displaying it in the table.
+ * </p>
+ *
+ * @param propertyId
+ * The propertyId to format using the converter
+ * @param converter
+ * The converter to use for the property id
+ */
+ public void setConverter(Object propertyId, Converter<String, ?> converter) {
+ if (!getContainerPropertyIds().contains(propertyId)) {
+ throw new IllegalArgumentException("PropertyId " + propertyId
+ + " must be in the container");
+ }
+ // FIXME: This check should be here but primitive types like Boolean
+ // formatter for boolean property must be handled
+
+ // if (!converter.getSourceType().isAssignableFrom(getType(propertyId)))
+ // {
+ // throw new IllegalArgumentException("Property type ("
+ // + getType(propertyId)
+ // + ") must match converter source type ("
+ // + converter.getSourceType() + ")");
+ // }
+ propertyValueConverters.put(propertyId,
+ (Converter<String, Object>) converter);
+ refreshRowCache();
+ }
+
+ /**
+ * Checks if there is a converter set explicitly for the given property id.
+ *
+ * @param propertyId
+ * The propertyId to check
+ * @return true if a converter has been set for the property id, false
+ * otherwise
+ */
+ protected boolean hasConverter(Object propertyId) {
+ return propertyValueConverters.containsKey(propertyId);
+ }
+
+ /**
+ * Returns the converter used to format the given propertyId.
+ *
+ * @param propertyId
+ * The propertyId to check
+ * @return The converter used to format the propertyId or null if no
+ * converter has been set
+ */
+ public Converter<String, Object> getConverter(Object propertyId) {
+ return propertyValueConverters.get(propertyId);
+ }
+
@Override
public void setVisible(boolean visible) {
if (!isVisible() && visible) {
diff --git a/src/com/vaadin/ui/TableFieldFactory.java b/src/com/vaadin/ui/TableFieldFactory.java
index 9b0495d589..6c9a641aa8 100644
--- a/src/com/vaadin/ui/TableFieldFactory.java
+++ b/src/com/vaadin/ui/TableFieldFactory.java
@@ -39,7 +39,7 @@ public interface TableFieldFactory extends Serializable {
* @return A field suitable for editing the specified data or null if the
* property should not be editable.
*/
- Field createField(Container container, Object itemId, Object propertyId,
+ Field<?> createField(Container container, Object itemId, Object propertyId,
Component uiContext);
}
diff --git a/src/com/vaadin/ui/TextArea.java b/src/com/vaadin/ui/TextArea.java
index e1e5aeabd4..a5e6bb5630 100644
--- a/src/com/vaadin/ui/TextArea.java
+++ b/src/com/vaadin/ui/TextArea.java
@@ -7,12 +7,12 @@ package com.vaadin.ui;
import com.vaadin.data.Property;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VTextArea;
+import com.vaadin.terminal.gwt.client.ui.VTextAreaPaintable;
/**
* A text field that supports multi line editing.
*/
-@ClientWidget(VTextArea.class)
+@ClientWidget(VTextAreaPaintable.class)
public class TextArea extends AbstractTextField {
private static final int DEFAULT_ROWS = 5;
diff --git a/src/com/vaadin/ui/TextField.java b/src/com/vaadin/ui/TextField.java
index 0d719efd12..a3d873336c 100644
--- a/src/com/vaadin/ui/TextField.java
+++ b/src/com/vaadin/ui/TextField.java
@@ -5,9 +5,7 @@
package com.vaadin.ui;
import com.vaadin.data.Property;
-import com.vaadin.terminal.PaintException;
-import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VTextField;
+import com.vaadin.terminal.gwt.client.ui.VTextFieldPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -31,30 +29,10 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VTextField.class, loadStyle = LoadStyle.EAGER)
+@ClientWidget(value = VTextFieldPaintable.class, loadStyle = LoadStyle.EAGER)
public class TextField extends AbstractTextField {
/**
- * Tells if input is used to enter sensitive information that is not echoed
- * to display. Typically passwords.
- */
- @Deprecated
- private boolean secret = false;
-
- /**
- * Number of visible rows in a multiline TextField. Value 0 implies a
- * single-line text-editor.
- */
- @Deprecated
- private int rows = 0;
-
- /**
- * Tells if word-wrapping should be used in multiline mode.
- */
- @Deprecated
- private boolean wordwrap = true;
-
- /**
* Constructs an empty <code>TextField</code> with no caption.
*/
public TextField() {
@@ -106,7 +84,7 @@ public class TextField extends AbstractTextField {
*
* @param caption
* the caption <code>String</code> for the editor.
- * @param text
+ * @param value
* the initial text content of the editor.
*/
public TextField(String caption, String value) {
@@ -114,180 +92,4 @@ public class TextField extends AbstractTextField {
setCaption(caption);
}
- /**
- * Gets the secret property. If a field is used to enter secret information
- * the information is not echoed to display.
- *
- * @return <code>true</code> if the field is used to enter secret
- * information, <code>false</code> otherwise.
- *
- * @deprecated Starting from 6.5 use {@link PasswordField} instead for
- * secret text input.
- */
- @Deprecated
- public boolean isSecret() {
- return secret;
- }
-
- /**
- * Sets the secret property on and off. If a field is used to enter secret
- * information the information is not echoed to display.
- *
- * @param secret
- * the value specifying if the field is used to enter secret
- * information.
- * @deprecated Starting from 6.5 use {@link PasswordField} instead for
- * secret text input.
- */
- @Deprecated
- public void setSecret(boolean secret) {
- if (this.secret != secret) {
- this.secret = secret;
- requestRepaint();
- }
- }
-
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- if (isSecret()) {
- target.addAttribute("secret", true);
- }
-
- final int rows = getRows();
- if (rows != 0) {
- target.addAttribute("rows", rows);
- target.addAttribute("multiline", true);
-
- if (!isWordwrap()) {
- // Wordwrap is only painted if turned off to minimize
- // communications
- target.addAttribute("wordwrap", false);
- }
- }
-
- super.paintContent(target);
-
- }
-
- /**
- * Gets the number of rows in the editor. If the number of rows is set to 0,
- * the actual number of displayed rows is determined implicitly by the
- * adapter.
- *
- * @return number of explicitly set rows.
- * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text
- * input.
- *
- */
- @Deprecated
- public int getRows() {
- return rows;
- }
-
- /**
- * Sets the number of rows in the editor.
- *
- * @param rows
- * the number of rows for this editor.
- *
- * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text
- * input.
- */
- @Deprecated
- public void setRows(int rows) {
- if (rows < 0) {
- rows = 0;
- }
- if (this.rows != rows) {
- this.rows = rows;
- requestRepaint();
- }
- }
-
- /**
- * Tests if the editor is in word-wrap mode.
- *
- * @return <code>true</code> if the component is in the word-wrap mode,
- * <code>false</code> if not.
- * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text
- * input.
- */
- @Deprecated
- public boolean isWordwrap() {
- return wordwrap;
- }
-
- /**
- * Sets the editor's word-wrap mode on or off.
- *
- * @param wordwrap
- * the boolean value specifying if the editor should be in
- * word-wrap mode after the call or not.
- *
- * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text
- * input.
- */
- @Deprecated
- public void setWordwrap(boolean wordwrap) {
- if (this.wordwrap != wordwrap) {
- this.wordwrap = wordwrap;
- requestRepaint();
- }
- }
-
- /**
- * Sets the height of the {@link TextField} instance.
- *
- * <p>
- * Setting height for {@link TextField} also has a side-effect that puts
- * {@link TextField} into multiline mode (aka "textarea"). Multiline mode
- * can also be achieved by calling {@link #setRows(int)}. The height value
- * overrides the number of rows set by {@link #setRows(int)}.
- * <p>
- * If you want to set height of single line {@link TextField}, call
- * {@link #setRows(int)} with value 0 after setting the height. Setting rows
- * to 0 resets the side-effect.
- * <p>
- * Starting from 6.5 you should use {@link TextArea} instead of
- * {@link TextField} for multiline text input.
- *
- *
- * @see com.vaadin.ui.AbstractComponent#setHeight(float, int)
- */
- @Override
- public void setHeight(float height, int unit) {
- super.setHeight(height, unit);
- if (height > 1 && getClass() == TextField.class) {
- /*
- * In html based terminals we most commonly want to make component
- * to be textarea if height is defined. Setting row field above 0
- * will render component as textarea.
- */
-
- setRows(2);
- }
- }
-
- /**
- * Sets the height of the {@link TextField} instance.
- *
- * <p>
- * Setting height for {@link TextField} also has a side-effect that puts
- * {@link TextField} into multiline mode (aka "textarea"). Multiline mode
- * can also be achieved by calling {@link #setRows(int)}. The height value
- * overrides the number of rows set by {@link #setRows(int)}.
- * <p>
- * If you want to set height of single line {@link TextField}, call
- * {@link #setRows(int)} with value 0 after setting the height. Setting rows
- * to 0 resets the side-effect.
- *
- * @see com.vaadin.ui.AbstractComponent#setHeight(java.lang.String)
- */
- @Override
- public void setHeight(String height) {
- // will call setHeight(float, int) the actually does the magic. Method
- // is overridden just to document side-effects.
- super.setHeight(height);
- }
-
}
diff --git a/src/com/vaadin/ui/Tree.java b/src/com/vaadin/ui/Tree.java
index 554afda97c..4ea66cc6bf 100644
--- a/src/com/vaadin/ui/Tree.java
+++ b/src/com/vaadin/ui/Tree.java
@@ -45,6 +45,7 @@ import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.VTree;
+import com.vaadin.terminal.gwt.client.ui.VTreePaintable;
import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
import com.vaadin.terminal.gwt.client.ui.dd.VTargetInSubtree;
import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
@@ -60,7 +61,7 @@ import com.vaadin.tools.ReflectTools;
* @since 3.0
*/
@SuppressWarnings({ "serial", "deprecation" })
-@ClientWidget(VTree.class)
+@ClientWidget(VTreePaintable.class)
public class Tree extends AbstractSelect implements Container.Hierarchical,
Action.Container, ItemClickSource, ItemClickNotifier, DragSource,
DropTarget {
diff --git a/src/com/vaadin/ui/TreeTable.java b/src/com/vaadin/ui/TreeTable.java
index 43bc7a80fe..09417e1e16 100644
--- a/src/com/vaadin/ui/TreeTable.java
+++ b/src/com/vaadin/ui/TreeTable.java
@@ -22,7 +22,7 @@ import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
-import com.vaadin.terminal.gwt.client.ui.VTreeTable;
+import com.vaadin.terminal.gwt.client.ui.VTreeTablePaintable;
import com.vaadin.ui.Tree.CollapseEvent;
import com.vaadin.ui.Tree.CollapseListener;
import com.vaadin.ui.Tree.ExpandEvent;
@@ -48,7 +48,7 @@ import com.vaadin.ui.treetable.HierarchicalContainerOrderedWrapper;
* share UI state in the container.
*/
@SuppressWarnings({ "serial" })
-@ClientWidget(VTreeTable.class)
+@ClientWidget(VTreeTablePaintable.class)
public class TreeTable extends Table implements Hierarchical {
private static final Logger logger = Logger.getLogger(TreeTable.class
@@ -454,7 +454,8 @@ public class TreeTable extends Table implements Hierarchical {
Object object = visibleColumns2[i];
if (hierarchyColumnId.equals(object)) {
target.addAttribute(
- VTreeTable.ATTRIBUTE_HIERARCHY_COLUMN_INDEX, i);
+ VTreeTablePaintable.ATTRIBUTE_HIERARCHY_COLUMN_INDEX,
+ i);
break;
}
}
diff --git a/src/com/vaadin/ui/TwinColSelect.java b/src/com/vaadin/ui/TwinColSelect.java
index 1c1fe07a5c..fbdd825a66 100644
--- a/src/com/vaadin/ui/TwinColSelect.java
+++ b/src/com/vaadin/ui/TwinColSelect.java
@@ -10,13 +10,14 @@ import com.vaadin.data.Container;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VTwinColSelect;
+import com.vaadin.terminal.gwt.client.ui.VTwinColSelectPaintable;
/**
* Multiselect component with two lists: left side for available items and right
* side for selected items.
*/
@SuppressWarnings("serial")
-@ClientWidget(VTwinColSelect.class)
+@ClientWidget(VTwinColSelectPaintable.class)
public class TwinColSelect extends AbstractSelect {
private int columns = 0;
diff --git a/src/com/vaadin/ui/Upload.java b/src/com/vaadin/ui/Upload.java
index 9d684291a5..08a8023ad5 100644
--- a/src/com/vaadin/ui/Upload.java
+++ b/src/com/vaadin/ui/Upload.java
@@ -15,7 +15,7 @@ import java.util.Map;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.StreamVariable.StreamingProgressEvent;
-import com.vaadin.terminal.gwt.client.ui.VUpload;
+import com.vaadin.terminal.gwt.client.ui.VUploadPaintable;
import com.vaadin.terminal.gwt.server.NoInputStreamException;
import com.vaadin.terminal.gwt.server.NoOutputStreamException;
import com.vaadin.ui.ClientWidget.LoadStyle;
@@ -61,7 +61,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VUpload.class, loadStyle = LoadStyle.LAZY)
+@ClientWidget(value = VUploadPaintable.class, loadStyle = LoadStyle.LAZY)
public class Upload extends AbstractComponent implements Component.Focusable {
/**
diff --git a/src/com/vaadin/ui/UriFragmentUtility.java b/src/com/vaadin/ui/UriFragmentUtility.java
deleted file mode 100644
index 5eaffbde6f..0000000000
--- a/src/com/vaadin/ui/UriFragmentUtility.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.ui;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.util.Map;
-
-import com.vaadin.terminal.PaintException;
-import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.VUriFragmentUtility;
-import com.vaadin.ui.ClientWidget.LoadStyle;
-
-/**
- * Experimental web browser dependent component for URI fragment (part after
- * hash mark "#") reading and writing.
- *
- * Component can be used to workaround common ajax web applications pitfalls:
- * bookmarking a program state and back button.
- *
- */
-@SuppressWarnings("serial")
-@ClientWidget(value = VUriFragmentUtility.class, loadStyle = LoadStyle.EAGER)
-public class UriFragmentUtility extends AbstractComponent {
-
- /**
- * Listener that listens changes in URI fragment.
- */
- public interface FragmentChangedListener extends Serializable {
-
- public void fragmentChanged(FragmentChangedEvent source);
-
- }
-
- /**
- * Event fired when uri fragment changes.
- */
- public class FragmentChangedEvent extends Component.Event {
-
- /**
- * Creates a new instance of UriFragmentReader change event.
- *
- * @param source
- * the Source of the event.
- */
- public FragmentChangedEvent(Component source) {
- super(source);
- }
-
- /**
- * Gets the UriFragmentReader where the event occurred.
- *
- * @return the Source of the event.
- */
- public UriFragmentUtility getUriFragmentUtility() {
- return (UriFragmentUtility) getSource();
- }
- }
-
- private static final Method FRAGMENT_CHANGED_METHOD;
-
- static {
- try {
- FRAGMENT_CHANGED_METHOD = FragmentChangedListener.class
- .getDeclaredMethod("fragmentChanged",
- new Class[] { FragmentChangedEvent.class });
- } catch (final java.lang.NoSuchMethodException e) {
- // This should never happen
- throw new java.lang.RuntimeException(
- "Internal error finding methods in FragmentChangedListener");
- }
- }
-
- public void addListener(FragmentChangedListener listener) {
- addListener(FragmentChangedEvent.class, listener,
- FRAGMENT_CHANGED_METHOD);
- }
-
- public void removeListener(FragmentChangedListener listener) {
- removeListener(FragmentChangedEvent.class, listener,
- FRAGMENT_CHANGED_METHOD);
- }
-
- private String fragment;
-
- public UriFragmentUtility() {
- // immediate by default
- setImmediate(true);
- }
-
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- super.paintContent(target);
- target.addVariable(this, "fragment", fragment);
- }
-
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
- super.changeVariables(source, variables);
- fragment = (String) variables.get("fragment");
- fireEvent(new FragmentChangedEvent(this));
- }
-
- /**
- * Gets currently set URI fragment.
- * <p>
- * To listen changes in fragment, hook a {@link FragmentChangedListener}.
- * <p>
- * Note that initial URI fragment that user used to enter the application
- * will be read after application init. It fires FragmentChangedEvent only
- * if it is not the same as on server side.
- *
- * @return the current fragment in browser uri or null if not known
- */
- public String getFragment() {
- return fragment;
- }
-
- /**
- * Sets URI fragment. Optionally fires a {@link FragmentChangedEvent}
- *
- * @param newFragment
- * id of the new fragment
- * @param fireEvent
- * true to fire event
- * @see FragmentChangedEvent
- * @see FragmentChangedListener
- */
- public void setFragment(String newFragment, boolean fireEvent) {
- if ((newFragment == null && fragment != null)
- || (newFragment != null && !newFragment.equals(fragment))) {
- fragment = newFragment;
- if (fireEvent) {
- fireEvent(new FragmentChangedEvent(this));
- }
- requestRepaint();
- }
- }
-
- /**
- * Sets URI fragment. This method fires a {@link FragmentChangedEvent}
- *
- * @param newFragment
- * id of the new fragment
- * @see FragmentChangedEvent
- * @see FragmentChangedListener
- */
- public void setFragment(String newFragment) {
- setFragment(newFragment, true);
- }
-
-}
diff --git a/src/com/vaadin/ui/VerticalLayout.java b/src/com/vaadin/ui/VerticalLayout.java
index c40aeaea30..0c5de43bbd 100644
--- a/src/com/vaadin/ui/VerticalLayout.java
+++ b/src/com/vaadin/ui/VerticalLayout.java
@@ -3,7 +3,7 @@
*/
package com.vaadin.ui;
-import com.vaadin.terminal.gwt.client.ui.VVerticalLayout;
+import com.vaadin.terminal.gwt.client.ui.VVerticalLayoutPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -19,7 +19,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* @since 5.3
*/
@SuppressWarnings("serial")
-@ClientWidget(value = VVerticalLayout.class, loadStyle = LoadStyle.EAGER)
+@ClientWidget(value = VVerticalLayoutPaintable.class, loadStyle = LoadStyle.EAGER)
public class VerticalLayout extends AbstractOrderedLayout {
public VerticalLayout() {
diff --git a/src/com/vaadin/ui/VerticalSplitPanel.java b/src/com/vaadin/ui/VerticalSplitPanel.java
index 699bd9287c..46e9d681e8 100644
--- a/src/com/vaadin/ui/VerticalSplitPanel.java
+++ b/src/com/vaadin/ui/VerticalSplitPanel.java
@@ -3,7 +3,7 @@
*/
package com.vaadin.ui;
-import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical;
+import com.vaadin.terminal.gwt.client.ui.VVerticalSplitPanelPaintable;
import com.vaadin.ui.ClientWidget.LoadStyle;
/**
@@ -23,7 +23,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
* </pre>
*
*/
-@ClientWidget(value = VSplitPanelVertical.class, loadStyle = LoadStyle.EAGER)
+@ClientWidget(value = VVerticalSplitPanelPaintable.class, loadStyle = LoadStyle.EAGER)
public class VerticalSplitPanel extends AbstractSplitPanel {
public VerticalSplitPanel() {
diff --git a/src/com/vaadin/ui/Video.java b/src/com/vaadin/ui/Video.java
index ed6588f96a..a2e71b1120 100644
--- a/src/com/vaadin/ui/Video.java
+++ b/src/com/vaadin/ui/Video.java
@@ -7,7 +7,7 @@ package com.vaadin.ui;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
-import com.vaadin.terminal.gwt.client.ui.VVideo;
+import com.vaadin.terminal.gwt.client.ui.VVideoPaintable;
/**
* The Video component translates into an HTML5 &lt;video&gt; element and as
@@ -30,7 +30,7 @@ import com.vaadin.terminal.gwt.client.ui.VVideo;
* @author Vaadin Ltd
* @since 6.7.0
*/
-@ClientWidget(VVideo.class)
+@ClientWidget(VVideoPaintable.class)
public class Video extends AbstractMedia {
private Resource poster;
@@ -80,7 +80,7 @@ public class Video extends AbstractMedia {
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
if (getPoster() != null) {
- target.addAttribute(VVideo.ATTR_POSTER, getPoster());
+ target.addAttribute(VVideoPaintable.ATTR_POSTER, getPoster());
}
}
}
diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java
index 7e33f91d31..a6cf51e80f 100644
--- a/src/com/vaadin/ui/Window.java
+++ b/src/com/vaadin/ui/Window.java
@@ -6,15 +6,7 @@ package com.vaadin.ui;
import java.io.Serializable;
import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
import java.util.Map;
-import java.util.Set;
import com.vaadin.Application;
import com.vaadin.event.FieldEvents.BlurEvent;
@@ -27,16 +19,11 @@ import com.vaadin.event.ShortcutAction;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
import com.vaadin.event.ShortcutListener;
-import com.vaadin.terminal.DownloadStream;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.ParameterHandler;
-import com.vaadin.terminal.Resource;
import com.vaadin.terminal.Sizeable;
-import com.vaadin.terminal.Terminal;
-import com.vaadin.terminal.URIHandler;
import com.vaadin.terminal.gwt.client.ui.VView;
-import com.vaadin.terminal.gwt.client.ui.VWindow;
+import com.vaadin.terminal.gwt.client.ui.VWindowPaintable;
/**
* A component that represents an application (browser native) window or a sub
@@ -84,79 +71,8 @@ import com.vaadin.terminal.gwt.client.ui.VWindow;
* @since 3.0
*/
@SuppressWarnings("serial")
-@ClientWidget(VWindow.class)
-public class Window extends Panel implements URIHandler, ParameterHandler,
- FocusNotifier, BlurNotifier {
-
- /**
- * <b>Application window only</b>. A border style used for opening resources
- * in a window without a border.
- */
- public static final int BORDER_NONE = 0;
-
- /**
- * <b>Application window only</b>. A border style used for opening resources
- * in a window with a minimal border.
- */
- public static final int BORDER_MINIMAL = 1;
-
- /**
- * <b>Application window only</b>. A border style that indicates that the
- * default border style should be used when opening resources.
- */
- public static final int BORDER_DEFAULT = 2;
-
- /**
- * <b>Application window only</b>. The user terminal for this window.
- */
- private Terminal terminal = null;
-
- /**
- * <b>Application window only</b>. The application this window is attached
- * to or null.
- */
- private Application application = null;
-
- /**
- * <b>Application window only</b>. List of URI handlers for this window.
- */
- private LinkedList<URIHandler> uriHandlerList = null;
-
- /**
- * <b>Application window only</b>. List of parameter handlers for this
- * window.
- */
- private LinkedList<ParameterHandler> parameterHandlerList = null;
-
- /**
- * <b>Application window only</b>. List of sub windows in this window. A sub
- * window cannot have other sub windows.
- */
- private final LinkedHashSet<Window> subwindows = new LinkedHashSet<Window>();
-
- /**
- * <b>Application window only</b>. Explicitly specified theme of this window
- * or null if the application theme should be used.
- */
- private String theme = null;
-
- /**
- * <b>Application window only</b>. Resources to be opened automatically on
- * next repaint. The list is automatically cleared when it has been sent to
- * the client.
- */
- private final LinkedList<OpenResource> openList = new LinkedList<OpenResource>();
-
- /**
- * <b>Application window only</b>. Unique name of the window used to
- * identify it.
- */
- private String name = null;
-
- /**
- * <b>Application window only.</b> Border mode of the Window.
- */
- private int border = BORDER_DEFAULT;
+@ClientWidget(VWindowPaintable.class)
+public class Window extends Panel implements FocusNotifier, BlurNotifier {
/**
* <b>Sub window only</b>. Top offset in pixels for the sub window (relative
@@ -171,13 +87,6 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
private int positionX = -1;
/**
- * <b>Application window only</b>. A list of notifications that are waiting
- * to be sent to the client. Cleared (set to null) when the notifications
- * have been sent.
- */
- private LinkedList<Notification> notifications;
-
- /**
* <b>Sub window only</b>. Modality flag for sub window.
*/
private boolean modal = false;
@@ -205,25 +114,6 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
private boolean resizeLazy = false;
/**
- * Component that should be focused after the next repaint. Null if no focus
- * change should take place.
- */
- private Focusable pendingFocus;
-
- /**
- * <b>Application window only</b>. A list of javascript commands that are
- * waiting to be sent to the client. Cleared (set to null) when the commands
- * have been sent.
- */
- private ArrayList<String> jsExecQueue = null;
-
- /**
- * The component that should be scrolled into view after the next repaint.
- * Null if nothing should be scrolled into view.
- */
- private Component scrollIntoView;
-
- /**
* Creates a new unnamed window with a default layout.
*/
public Window() {
@@ -269,288 +159,8 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
super.addComponent(c);
}
- /**
- * <b>Application window only</b>. Gets the user terminal.
- *
- * @return the user terminal
- */
- public Terminal getTerminal() {
- return terminal;
- }
-
/* ********************************************************************* */
- /**
- * Gets the parent window of the component.
- * <p>
- * This is always the window itself.
- * </p>
- * <p>
- * <b>This method is not meant to be overridden. Due to CDI requirements we
- * cannot declare it as final even though it should be final.</b>
- * </p>
- *
- * @see Component#getWindow()
- * @return the window itself
- */
- @Override
- public Window getWindow() {
- return this;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.AbstractComponent#getApplication()
- */
- @Override
- public Application getApplication() {
- if (getParent() == null) {
- return application;
- }
- return getParent().getApplication();
- }
-
- /**
- * Gets the parent component of the window.
- *
- * <p>
- * The parent of an application window is always null. The parent of a sub
- * window is the application window the sub window is attached to.
- * </p>
- * <p>
- * <b>This method is not meant to be overridden. Due to CDI requirements we
- * cannot declare it as final even though it should be final.</b>
- * </p>
- *
- *
- * @return the parent window
- * @see Component#getParent()
- */
- @Override
- public Window getParent() {
- return (Window) super.getParent();
- }
-
- /* ********************************************************************* */
-
- /**
- * <b>Application window only</b>. Adds a new URI handler to this window. If
- * this is a sub window the URI handler is attached to the parent
- * application window.
- *
- * @param handler
- * the URI handler to add.
- */
- public void addURIHandler(URIHandler handler) {
- if (getParent() != null) {
- // this is subwindow, attach to main level instead
- // TODO hold internal list also and remove on detach
- Window mainWindow = getParent();
- mainWindow.addURIHandler(handler);
- } else {
- if (uriHandlerList == null) {
- uriHandlerList = new LinkedList<URIHandler>();
- }
- synchronized (uriHandlerList) {
- if (!uriHandlerList.contains(handler)) {
- uriHandlerList.addLast(handler);
- }
- }
- }
- }
-
- /**
- * <b>Application window only</b>. Removes the URI handler from this window.
- * If this is a sub window the URI handler is removed from the parent
- * application window.
- *
- * @param handler
- * the URI handler to remove.
- */
- public void removeURIHandler(URIHandler handler) {
- if (getParent() != null) {
- // this is subwindow
- Window mainWindow = getParent();
- mainWindow.removeURIHandler(handler);
- } else {
- if (handler == null || uriHandlerList == null) {
- return;
- }
- synchronized (uriHandlerList) {
- uriHandlerList.remove(handler);
- if (uriHandlerList.isEmpty()) {
- uriHandlerList = null;
- }
- }
- }
- }
-
- /**
- * <b>Application window only</b>. Handles an URI by passing the URI to all
- * URI handlers defined using {@link #addURIHandler(URIHandler)}. All URI
- * handlers are called for each URI but no more than one handler may return
- * a {@link DownloadStream}. If more than one stream is returned a
- * {@code RuntimeException} is thrown.
- *
- * @param context
- * The URL of the application
- * @param relativeUri
- * The URI relative to {@code context}
- * @return A {@code DownloadStream} that one of the URI handlers returned,
- * null if no {@code DownloadStream} was returned.
- */
- public DownloadStream handleURI(URL context, String relativeUri) {
-
- DownloadStream result = null;
- if (uriHandlerList != null) {
- Object[] handlers;
- synchronized (uriHandlerList) {
- handlers = uriHandlerList.toArray();
- }
- for (int i = 0; i < handlers.length; i++) {
- final DownloadStream ds = ((URIHandler) handlers[i]).handleURI(
- context, relativeUri);
- if (ds != null) {
- if (result != null) {
- throw new RuntimeException("handleURI for " + context
- + " uri: '" + relativeUri
- + "' returns ambigious result.");
- }
- result = ds;
- }
- }
- }
- return result;
- }
-
- /* ********************************************************************* */
-
- /**
- * <b>Application window only</b>. Adds a new parameter handler to this
- * window. If this is a sub window the parameter handler is attached to the
- * parent application window.
- *
- * @param handler
- * the parameter handler to add.
- */
- public void addParameterHandler(ParameterHandler handler) {
- if (getParent() != null) {
- // this is subwindow
- // TODO hold internal list also and remove on detach
- Window mainWindow = getParent();
- mainWindow.addParameterHandler(handler);
- } else {
- if (parameterHandlerList == null) {
- parameterHandlerList = new LinkedList<ParameterHandler>();
- }
- synchronized (parameterHandlerList) {
- if (!parameterHandlerList.contains(handler)) {
- parameterHandlerList.addLast(handler);
- }
- }
- }
-
- }
-
- /**
- * <b>Application window only</b>. Removes the parameter handler from this
- * window. If this is a sub window the parameter handler is removed from the
- * parent application window.
- *
- * @param handler
- * the parameter handler to remove.
- */
- public void removeParameterHandler(ParameterHandler handler) {
- if (getParent() != null) {
- // this is subwindow
- Window mainWindow = getParent();
- mainWindow.removeParameterHandler(handler);
- } else {
- if (handler == null || parameterHandlerList == null) {
- return;
- }
- synchronized (parameterHandlerList) {
- parameterHandlerList.remove(handler);
- if (parameterHandlerList.isEmpty()) {
- parameterHandlerList = null;
- }
- }
- }
- }
-
- /**
- * <b>Application window only</b>. Handles parameters by passing the
- * parameters to all {@code ParameterHandler}s defined using
- * {@link #addParameterHandler(ParameterHandler)}. All
- * {@code ParameterHandler}s are called for each set of parameters.
- *
- * @param parameters
- * a map containing the parameter names and values
- * @see ParameterHandler#handleParameters(Map)
- */
- public void handleParameters(Map<String, String[]> parameters) {
- if (parameterHandlerList != null) {
- Object[] handlers;
- synchronized (parameterHandlerList) {
- handlers = parameterHandlerList.toArray();
- }
- for (int i = 0; i < handlers.length; i++) {
- ((ParameterHandler) handlers[i]).handleParameters(parameters);
- }
- }
- }
-
- /* ********************************************************************* */
-
- /**
- * <b>Application window only</b>. Gets the theme for this window.
- * <p>
- * If the theme for this window is not explicitly set, the application theme
- * name is returned. If the window is not attached to an application, the
- * terminal default theme name is returned. If the theme name cannot be
- * determined, null is returned
- * </p>
- * <p>
- * Subwindows do not support themes and return the theme used by the parent
- * window
- * </p>
- *
- * @return the name of the theme used for the window
- */
- public String getTheme() {
- if (getParent() != null) {
- return (getParent()).getTheme();
- }
- if (theme != null) {
- return theme;
- }
- if ((application != null) && (application.getTheme() != null)) {
- return application.getTheme();
- }
- if (terminal != null) {
- return terminal.getDefaultTheme();
- }
- return null;
- }
-
- /**
- * <b>Application window only</b>. Sets the name of the theme to use for
- * this window. Changing the theme will cause the page to be reloaded.
- *
- * @param theme
- * the name of the new theme for this window or null to use the
- * application theme.
- */
- public void setTheme(String theme) {
- if (getParent() != null) {
- throw new UnsupportedOperationException(
- "Setting theme for sub-windows is not supported.");
- }
- this.theme = theme;
- requestRepaint();
- }
-
/*
* (non-Javadoc)
*
@@ -560,14 +170,6 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
public synchronized void paintContent(PaintTarget target)
throws PaintException {
- // Sets the window name
- final String name = getName();
- target.addAttribute("name", name == null ? "" : name);
-
- // Sets the window theme
- final String theme = getTheme();
- target.addAttribute("theme", theme == null ? "" : theme);
-
if (modal) {
target.addAttribute("modal", true);
}
@@ -594,17 +196,6 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
centerRequested = false;
}
- if (scrollIntoView != null) {
- target.addAttribute("scrollTo", scrollIntoView);
- scrollIntoView = null;
- }
-
- // Marks the main window
- if (getApplication() != null
- && this == getApplication().getMainWindow()) {
- target.addAttribute("main", true);
- }
-
if (getContent() != null) {
if (getContent().getHeightUnits() == Sizeable.UNITS_PERCENTAGE) {
target.addAttribute("layoutRelativeHeight", true);
@@ -614,450 +205,15 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
}
}
- // Open requested resource
- synchronized (openList) {
- if (!openList.isEmpty()) {
- for (final Iterator<OpenResource> i = openList.iterator(); i
- .hasNext();) {
- (i.next()).paintContent(target);
- }
- openList.clear();
- }
- }
-
// Contents of the window panel is painted
super.paintContent(target);
- // Add executable javascripts if needed
- if (jsExecQueue != null) {
- for (String script : jsExecQueue) {
- target.startTag("execJS");
- target.addAttribute("script", script);
- target.endTag("execJS");
- }
- jsExecQueue = null;
- }
-
// Window position
target.addVariable(this, "positionx", getPositionX());
target.addVariable(this, "positiony", getPositionY());
// Window closing
target.addVariable(this, "close", false);
-
- if (getParent() == null) {
- // Paint subwindows
- for (final Iterator<Window> i = subwindows.iterator(); i.hasNext();) {
- final Window w = i.next();
- w.paint(target);
- }
- } else {
- // mark subwindows
- target.addAttribute("sub", true);
- }
-
- // Paint notifications
- if (notifications != null) {
- target.startTag("notifications");
- for (final Iterator<Notification> it = notifications.iterator(); it
- .hasNext();) {
- final Notification n = it.next();
- target.startTag("notification");
- if (n.getCaption() != null) {
- target.addAttribute("caption", n.getCaption());
- }
- if (n.getMessage() != null) {
- target.addAttribute("message", n.getMessage());
- }
- if (n.getIcon() != null) {
- target.addAttribute("icon", n.getIcon());
- }
- if (!n.isHtmlContentAllowed()) {
- target.addAttribute(
- VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, true);
- }
- target.addAttribute("position", n.getPosition());
- target.addAttribute("delay", n.getDelayMsec());
- if (n.getStyleName() != null) {
- target.addAttribute("style", n.getStyleName());
- }
- target.endTag("notification");
- }
- target.endTag("notifications");
- notifications = null;
- }
-
- if (pendingFocus != null) {
- // ensure focused component is still attached to this main window
- if (pendingFocus.getWindow() == this
- || (pendingFocus.getWindow() != null && pendingFocus
- .getWindow().getParent() == this)) {
- target.addAttribute("focused", pendingFocus);
- }
- pendingFocus = null;
- }
-
- }
-
- /* ********************************************************************* */
-
- /**
- * Scrolls any component between the component and window to a suitable
- * position so the component is visible to the user. The given component
- * must be inside this window.
- *
- * @param component
- * the component to be scrolled into view
- * @throws IllegalArgumentException
- * if {@code component} is not inside this window
- */
- public void scrollIntoView(Component component)
- throws IllegalArgumentException {
- if (component.getWindow() != this) {
- throw new IllegalArgumentException(
- "The component where to scroll must be inside this window.");
- }
- scrollIntoView = component;
- requestRepaint();
- }
-
- /**
- * Opens the given resource in this window. The contents of this Window is
- * replaced by the {@code Resource}.
- *
- * @param resource
- * the resource to show in this window
- */
- public void open(Resource resource) {
- synchronized (openList) {
- if (!openList.contains(resource)) {
- openList.add(new OpenResource(resource, null, -1, -1,
- BORDER_DEFAULT));
- }
- }
- requestRepaint();
- }
-
- /* ********************************************************************* */
-
- /**
- * Opens the given resource in a window with the given name.
- * <p>
- * The supplied {@code windowName} is used as the target name in a
- * window.open call in the client. This means that special values such as
- * "_blank", "_self", "_top", "_parent" have special meaning. An empty or
- * <code>null</code> window name is also a special case.
- * </p>
- * <p>
- * "", null and "_self" as {@code windowName} all causes the resource to be
- * opened in the current window, replacing any old contents. For
- * downloadable content you should avoid "_self" as "_self" causes the
- * client to skip rendering of any other changes as it considers them
- * irrelevant (the page will be replaced by the resource). This can speed up
- * the opening of a resource, but it might also put the client side into an
- * inconsistent state if the window content is not completely replaced e.g.,
- * if the resource is downloaded instead of displayed in the browser.
- * </p>
- * <p>
- * "_blank" as {@code windowName} causes the resource to always be opened in
- * a new window or tab (depends on the browser and browser settings).
- * </p>
- * <p>
- * "_top" and "_parent" as {@code windowName} works as specified by the HTML
- * standard.
- * </p>
- * <p>
- * Any other {@code windowName} will open the resource in a window with that
- * name, either by opening a new window/tab in the browser or by replacing
- * the contents of an existing window with that name.
- * </p>
- *
- * @param resource
- * the resource.
- * @param windowName
- * the name of the window.
- */
- public void open(Resource resource, String windowName) {
- synchronized (openList) {
- if (!openList.contains(resource)) {
- openList.add(new OpenResource(resource, windowName, -1, -1,
- BORDER_DEFAULT));
- }
- }
- requestRepaint();
- }
-
- /**
- * Opens the given resource in a window with the given size, border and
- * name. For more information on the meaning of {@code windowName}, see
- * {@link #open(Resource, String)}.
- *
- * @param resource
- * the resource.
- * @param windowName
- * the name of the window.
- * @param width
- * the width of the window in pixels
- * @param height
- * the height of the window in pixels
- * @param border
- * the border style of the window. See {@link #BORDER_NONE
- * Window.BORDER_* constants}
- */
- public void open(Resource resource, String windowName, int width,
- int height, int border) {
- synchronized (openList) {
- if (!openList.contains(resource)) {
- openList.add(new OpenResource(resource, windowName, width,
- height, border));
- }
- }
- requestRepaint();
- }
-
- /* ********************************************************************* */
-
- /**
- * Gets the full URL of the window. The returned URL is window specific and
- * can be used to directly refer to the window.
- * <p>
- * Note! This method can not be used for portlets.
- * </p>
- *
- * @return the URL of the window or null if the window is not attached to an
- * application
- */
- public URL getURL() {
-
- if (application == null) {
- return null;
- }
-
- try {
- return new URL(application.getURL(), getName() + "/");
- } catch (final MalformedURLException e) {
- throw new RuntimeException(
- "Internal problem getting window URL, please report");
- }
- }
-
- /**
- * <b>Application window only</b>. Gets the unique name of the window. The
- * name of the window is used to uniquely identify it.
- * <p>
- * The name also determines the URL that can be used for direct access to a
- * window. All windows can be accessed through
- * {@code http://host:port/app/win} where {@code http://host:port/app} is
- * the application URL (as returned by {@link Application#getURL()} and
- * {@code win} is the window name.
- * </p>
- * <p>
- * Note! Portlets do not support direct window access through URLs.
- * </p>
- *
- * @return the Name of the Window.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the border style of the window.
- *
- * @see #setBorder(int)
- * @return the border style for the window
- */
- public int getBorder() {
- return border;
- }
-
- /**
- * Sets the border style for this window. Valid values are
- * {@link Window#BORDER_NONE}, {@link Window#BORDER_MINIMAL},
- * {@link Window#BORDER_DEFAULT}.
- * <p>
- * <b>Note!</b> Setting this seems to currently have no effect whatsoever on
- * the window.
- * </p>
- *
- * @param border
- * the border style to set
- */
- public void setBorder(int border) {
- this.border = border;
- }
-
- /**
- * Sets the application this window is attached to.
- *
- * <p>
- * This method is called by the framework and should not be called directly
- * from application code. {@link com.vaadin.Application#addWindow(Window)}
- * should be used to add the window to an application and
- * {@link com.vaadin.Application#removeWindow(Window)} to remove the window
- * from the application.
- * </p>
- * <p>
- * This method invokes {@link Component#attach()} and
- * {@link Component#detach()} methods when necessary.
- * <p>
- *
- * @param application
- * the application the window is attached to
- */
- public void setApplication(Application application) {
-
- // If the application is not changed, dont do nothing
- if (application == this.application) {
- return;
- }
-
- // Sends detach event if the window is connected to application
- if (this.application != null) {
- detach();
- }
-
- // Connects to new parent
- this.application = application;
-
- // Sends the attach event if connected to a window
- if (application != null) {
- attach();
- }
- }
-
- /**
- * <b>Application window only</b>. Sets the unique name of the window. The
- * name of the window is used to uniquely identify it inside the
- * application.
- * <p>
- * The name also determines the URL that can be used for direct access to a
- * window. All windows can be accessed through
- * {@code http://host:port/app/win} where {@code http://host:port/app} is
- * the application URL (as returned by {@link Application#getURL()} and
- * {@code win} is the window name.
- * </p>
- * <p>
- * This method can only be called before the window is added to an
- * application.
- * </p>
- * <p>
- * Note! Portlets do not support direct window access through URLs.
- * </p>
- *
- * @param name
- * the new name for the window or null if the application should
- * automatically assign a name to it
- * @throws IllegalStateException
- * if the window is attached to an application
- */
- public void setName(String name) throws IllegalStateException {
-
- // The name can not be changed in application
- if (getApplication() != null) {
- throw new IllegalStateException(
- "Window name can not be changed while "
- + "the window is in application");
- }
-
- this.name = name;
- }
-
- /**
- * Sets the user terminal. Used by the terminal adapter, should never be
- * called from application code.
- *
- * @param type
- * the terminal to set.
- */
- public void setTerminal(Terminal type) {
- terminal = type;
- }
-
- /**
- * Private class for storing properties related to opening resources.
- */
- private class OpenResource implements Serializable {
-
- /**
- * The resource to open
- */
- private final Resource resource;
-
- /**
- * The name of the target window
- */
- private final String name;
-
- /**
- * The width of the target window
- */
- private final int width;
-
- /**
- * The height of the target window
- */
- private final int height;
-
- /**
- * The border style of the target window
- */
- private final int border;
-
- /**
- * Creates a new open resource.
- *
- * @param resource
- * The resource to open
- * @param name
- * The name of the target window
- * @param width
- * The width of the target window
- * @param height
- * The height of the target window
- * @param border
- * The border style of the target window
- */
- private OpenResource(Resource resource, String name, int width,
- int height, int border) {
- this.resource = resource;
- this.name = name;
- this.width = width;
- this.height = height;
- this.border = border;
- }
-
- /**
- * Paints the open request. Should be painted inside the window.
- *
- * @param target
- * the paint target
- * @throws PaintException
- * if the paint operation fails
- */
- private void paintContent(PaintTarget target) throws PaintException {
- target.startTag("open");
- target.addAttribute("src", resource);
- if (name != null && name.length() > 0) {
- target.addAttribute("name", name);
- }
- if (width >= 0) {
- target.addAttribute("width", width);
- }
- if (height >= 0) {
- target.addAttribute("height", height);
- }
- switch (border) {
- case Window.BORDER_MINIMAL:
- target.addAttribute("border", "minimal");
- break;
- case Window.BORDER_NONE:
- target.addAttribute("border", "none");
- break;
- }
-
- target.endTag("open");
- }
}
/*
@@ -1068,6 +224,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
@Override
public void changeVariables(Object source, Map<String, Object> variables) {
+ // TODO Are these for top level windows or sub windows?
boolean sizeHasChanged = false;
// size is handled in super class, but resize events only in windows ->
// so detect if size change occurs before super.changeVariables()
@@ -1137,17 +294,15 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
* {@link CloseListener}.
* </p>
*/
- protected void close() {
- Window parent = getParent();
- if (parent == null) {
- fireClose();
- } else {
+ public void close() {
+ Root root = getRoot();
+ // Don't do anything if not attached to a root
+ if (root != null) {
// focus is restored to the parent window
- parent.focus();
-
- // subwindow is removed from parent
- parent.removeWindow(this);
+ root.focus();
+ // subwindow is removed from the root
+ root.removeWindow(this);
}
}
@@ -1413,128 +568,45 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
fireEvent(new ResizeEvent(this));
}
- private void attachWindow(Window w) {
- subwindows.add(w);
- w.setParent(this);
- requestRepaint();
- }
-
/**
- * Adds a window inside another window.
- *
- * <p>
- * Adding windows inside another window creates "subwindows". These windows
- * should not be added to application directly and are not accessible
- * directly with any url. Addding windows implicitly sets their parents.
- * </p>
- *
- * <p>
- * Only one level of subwindows are supported. Thus you can add windows
- * inside such windows whose parent is <code>null</code>.
- * </p>
- *
- * @param window
- * @throws IllegalArgumentException
- * if a window is added inside non-application level window.
- * @throws NullPointerException
- * if the given <code>Window</code> is <code>null</code>.
- */
- public void addWindow(Window window) throws IllegalArgumentException,
- NullPointerException {
-
- if (window == null) {
- throw new NullPointerException("Argument must not be null");
- }
-
- if (window.getApplication() != null) {
- throw new IllegalArgumentException(
- "Window was already added to application"
- + " - it can not be added to another window also.");
- } else if (getParent() != null) {
- throw new IllegalArgumentException(
- "You can only add windows inside application-level windows.");
- } else if (window.subwindows.size() > 0) {
- throw new IllegalArgumentException(
- "Only one level of subwindows are supported.");
- }
-
- attachWindow(window);
- }
-
- /**
- * Remove the given subwindow from this window.
- *
- * Since Vaadin 6.5, {@link CloseListener}s are called also when explicitly
- * removing a window by calling this method.
- *
- * Since Vaadin 6.5, returns a boolean indicating if the window was removed
- * or not.
- *
- * @param window
- * Window to be removed.
- * @return true if the subwindow was removed, false otherwise
- */
- public boolean removeWindow(Window window) {
- if (!subwindows.remove(window)) {
- // Window window is not a subwindow of this window.
- return false;
- }
- window.setParent(null);
- window.fireClose();
- requestRepaint();
-
- return true;
- }
-
- private Integer bringToFront = null;
-
- /*
- * This sequesnce is used to keep the right order of windows if multiple
- * windows are brought to front in a single changeset. Incremented and saved
- * by childwindows. If sequence is not used, the order is quite random
- * (depends on the order getting to dirty list. e.g. which window got
+ * Used to keep the right order of windows if multiple windows are brought
+ * to front in a single changeset. If this is not used, the order is quite
+ * random (depends on the order getting to dirty list. e.g. which window got
* variable changes).
*/
- private int bringToFrontSequence = 0;
+ private Integer bringToFront = null;
/**
- * If there are currently several sub windows visible, calling this method
- * makes this window topmost.
+ * If there are currently several windows visible, calling this method makes
+ * this window topmost.
* <p>
- * This method can only be called if this window is a sub window and
- * connected a top level window. Else an illegal state exception is thrown.
- * Also if there are modal windows and this window is not modal, and illegal
- * state exception is thrown.
+ * This method can only be called if this window connected a root. Else an
+ * illegal state exception is thrown. Also if there are modal windows and
+ * this window is not modal, and illegal state exception is thrown.
* <p>
- * <strong> Note, this API works on sub windows only. Browsers can't reorder
- * OS windows.</strong>
*/
public void bringToFront() {
- Window parent = getParent();
- if (parent == null) {
+ Root root = getRoot();
+ if (root == null) {
throw new IllegalStateException(
"Window must be attached to parent before calling bringToFront method.");
}
- for (Window w : parent.getChildWindows()) {
- if (w.isModal() && !isModal()) {
+ int maxBringToFront = -1;
+ for (Window w : root.getWindows()) {
+ if (!isModal() && w.isModal()) {
throw new IllegalStateException(
- "There are modal windows currently visible, non-modal window cannot be brought to front.");
+ "The root contains modal windows, non-modal window cannot be brought to front.");
+ }
+ if (w.bringToFront != null) {
+ maxBringToFront = Math.max(maxBringToFront,
+ w.bringToFront.intValue());
}
}
- bringToFront = getParent().bringToFrontSequence++;
+ bringToFront = Integer.valueOf(maxBringToFront + 1);
requestRepaint();
}
/**
- * Get the set of all child windows.
- *
- * @return Set of child windows.
- */
- public Set<Window> getChildWindows() {
- return Collections.unmodifiableSet(subwindows);
- }
-
- /**
* Sets sub-window modal, so that widgets behind it cannot be accessed.
* <b>Note:</b> affects sub-windows only.
*
@@ -1609,533 +681,6 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
}
/**
- * Shows a notification message on the middle of the window. The message
- * automatically disappears ("humanized message").
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption is
- * rendered as html.
- *
- * @see #showNotification(com.vaadin.ui.Window.Notification)
- * @see Notification
- *
- * @param caption
- * The message
- */
- public void showNotification(String caption) {
- addNotification(new Notification(caption));
- }
-
- /**
- * Shows a notification message the window. The position and behavior of the
- * message depends on the type, which is one of the basic types defined in
- * {@link Notification}, for instance Notification.TYPE_WARNING_MESSAGE.
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption is
- * rendered as html.
- *
- * @see #showNotification(com.vaadin.ui.Window.Notification)
- * @see Notification
- *
- * @param caption
- * The message
- * @param type
- * The message type
- */
- public void showNotification(String caption, int type) {
- addNotification(new Notification(caption, type));
- }
-
- /**
- * Shows a notification consisting of a bigger caption and a smaller
- * description on the middle of the window. The message automatically
- * disappears ("humanized message").
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption and
- * description are rendered as html.
- *
- * @see #showNotification(com.vaadin.ui.Window.Notification)
- * @see Notification
- *
- * @param caption
- * The caption of the message
- * @param description
- * The message description
- *
- */
- public void showNotification(String caption, String description) {
- addNotification(new Notification(caption, description));
- }
-
- /**
- * Shows a notification consisting of a bigger caption and a smaller
- * description. The position and behavior of the message depends on the
- * type, which is one of the basic types defined in {@link Notification},
- * for instance Notification.TYPE_WARNING_MESSAGE.
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption and
- * description are rendered as html.
- *
- * @see #showNotification(com.vaadin.ui.Window.Notification)
- * @see Notification
- *
- * @param caption
- * The caption of the message
- * @param description
- * The message description
- * @param type
- * The message type
- */
- public void showNotification(String caption, String description, int type) {
- addNotification(new Notification(caption, description, type));
- }
-
- /**
- * Shows a notification consisting of a bigger caption and a smaller
- * description. The position and behavior of the message depends on the
- * type, which is one of the basic types defined in {@link Notification},
- * for instance Notification.TYPE_WARNING_MESSAGE.
- *
- * Care should be taken to avoid XSS vulnerabilities if html content is
- * allowed.
- *
- * @see #showNotification(com.vaadin.ui.Window.Notification)
- * @see Notification
- *
- * @param caption
- * The message caption
- * @param description
- * The message description
- * @param type
- * The type of message
- * @param htmlContentAllowed
- * Whether html in the caption and description should be
- * displayed as html or as plain text
- */
- public void showNotification(String caption, String description, int type,
- boolean htmlContentAllowed) {
- addNotification(new Notification(caption, description, type,
- htmlContentAllowed));
- }
-
- /**
- * Shows a notification message.
- *
- * @see Notification
- * @see #showNotification(String)
- * @see #showNotification(String, int)
- * @see #showNotification(String, String)
- * @see #showNotification(String, String, int)
- *
- * @param notification
- * The notification message to show
- */
- public void showNotification(Notification notification) {
- addNotification(notification);
- }
-
- private void addNotification(Notification notification) {
- if (notifications == null) {
- notifications = new LinkedList<Notification>();
- }
- notifications.add(notification);
- requestRepaint();
- }
-
- /**
- * This method is used by Component.Focusable objects to request focus to
- * themselves. Focus renders must be handled at window level (instead of
- * Component.Focusable) due we want the last focused component to be focused
- * in client too. Not the one that is rendered last (the case we'd get if
- * implemented in Focusable only).
- *
- * To focus component from Vaadin application, use Focusable.focus(). See
- * {@link Focusable}.
- *
- * @param focusable
- * to be focused on next paint
- */
- void setFocusedComponent(Focusable focusable) {
- if (getParent() != null) {
- // focus is handled by main windows
- (getParent()).setFocusedComponent(focusable);
- } else {
- pendingFocus = focusable;
- requestRepaint();
- }
- }
-
- /**
- * A notification message, used to display temporary messages to the user -
- * for example "Document saved", or "Save failed".
- * <p>
- * The notification message can consist of several parts: caption,
- * description and icon. It is usually used with only caption - one should
- * be wary of filling the notification with too much information.
- * </p>
- * <p>
- * The notification message tries to be as unobtrusive as possible, while
- * still drawing needed attention. There are several basic types of messages
- * that can be used in different situations:
- * <ul>
- * <li>TYPE_HUMANIZED_MESSAGE fades away quickly as soon as the user uses
- * the mouse or types something. It can be used to show fairly unimportant
- * messages, such as feedback that an operation succeeded ("Document Saved")
- * - the kind of messages the user ignores once the application is familiar.
- * </li>
- * <li>TYPE_WARNING_MESSAGE is shown for a short while after the user uses
- * the mouse or types something. It's default style is also more noticeable
- * than the humanized message. It can be used for messages that do not
- * contain a lot of important information, but should be noticed by the
- * user. Despite the name, it does not have to be a warning, but can be used
- * instead of the humanized message whenever you want to make the message a
- * little more noticeable.</li>
- * <li>TYPE_ERROR_MESSAGE requires to user to click it before disappearing,
- * and can be used for critical messages.</li>
- * <li>TYPE_TRAY_NOTIFICATION is shown for a while in the lower left corner
- * of the window, and can be used for "convenience notifications" that do
- * not have to be noticed immediately, and should not interfere with the
- * current task - for instance to show "You have a new message in your
- * inbox" while the user is working in some other area of the application.</li>
- * </ul>
- * </p>
- * <p>
- * In addition to the basic pre-configured types, a Notification can also be
- * configured to show up in a custom position, for a specified time (or
- * until clicked), and with a custom stylename. An icon can also be added.
- * </p>
- *
- */
- public static class Notification implements Serializable {
- public static final int TYPE_HUMANIZED_MESSAGE = 1;
- public static final int TYPE_WARNING_MESSAGE = 2;
- public static final int TYPE_ERROR_MESSAGE = 3;
- public static final int TYPE_TRAY_NOTIFICATION = 4;
-
- public static final int POSITION_CENTERED = 1;
- public static final int POSITION_CENTERED_TOP = 2;
- public static final int POSITION_CENTERED_BOTTOM = 3;
- public static final int POSITION_TOP_LEFT = 4;
- public static final int POSITION_TOP_RIGHT = 5;
- public static final int POSITION_BOTTOM_LEFT = 6;
- public static final int POSITION_BOTTOM_RIGHT = 7;
-
- public static final int DELAY_FOREVER = -1;
- public static final int DELAY_NONE = 0;
-
- private String caption;
- private String description;
- private Resource icon;
- private int position = POSITION_CENTERED;
- private int delayMsec = 0;
- private String styleName;
- private boolean htmlContentAllowed;
-
- /**
- * Creates a "humanized" notification message.
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption
- * is by default rendered as html.
- *
- * @param caption
- * The message to show
- */
- public Notification(String caption) {
- this(caption, null, TYPE_HUMANIZED_MESSAGE);
- }
-
- /**
- * Creates a notification message of the specified type.
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption
- * is by default rendered as html.
- *
- * @param caption
- * The message to show
- * @param type
- * The type of message
- */
- public Notification(String caption, int type) {
- this(caption, null, type);
- }
-
- /**
- * Creates a "humanized" notification message with a bigger caption and
- * smaller description.
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption
- * and description are by default rendered as html.
- *
- * @param caption
- * The message caption
- * @param description
- * The message description
- */
- public Notification(String caption, String description) {
- this(caption, description, TYPE_HUMANIZED_MESSAGE);
- }
-
- /**
- * Creates a notification message of the specified type, with a bigger
- * caption and smaller description.
- *
- * Care should be taken to to avoid XSS vulnerabilities as the caption
- * and description are by default rendered as html.
- *
- * @param caption
- * The message caption
- * @param description
- * The message description
- * @param type
- * The type of message
- */
- public Notification(String caption, String description, int type) {
- this(caption, description, type, true);
- }
-
- /**
- * Creates a notification message of the specified type, with a bigger
- * caption and smaller description.
- *
- * Care should be taken to to avoid XSS vulnerabilities if html is
- * allowed.
- *
- * @param caption
- * The message caption
- * @param description
- * The message description
- * @param type
- * The type of message
- * @param htmlContentAllowed
- * Whether html in the caption and description should be
- * displayed as html or as plain text
- */
- public Notification(String caption, String description, int type,
- boolean htmlContentAllowed) {
- this.caption = caption;
- this.description = description;
- this.htmlContentAllowed = htmlContentAllowed;
- setType(type);
- }
-
- private void setType(int type) {
- switch (type) {
- case TYPE_WARNING_MESSAGE:
- delayMsec = 1500;
- styleName = "warning";
- break;
- case TYPE_ERROR_MESSAGE:
- delayMsec = -1;
- styleName = "error";
- break;
- case TYPE_TRAY_NOTIFICATION:
- delayMsec = 3000;
- position = POSITION_BOTTOM_RIGHT;
- styleName = "tray";
-
- case TYPE_HUMANIZED_MESSAGE:
- default:
- break;
- }
-
- }
-
- /**
- * Gets the caption part of the notification message.
- *
- * @return The message caption
- */
- public String getCaption() {
- return caption;
- }
-
- /**
- * Sets the caption part of the notification message
- *
- * @param caption
- * The message caption
- */
- public void setCaption(String caption) {
- this.caption = caption;
- }
-
- /**
- * @deprecated Use {@link #getDescription()} instead.
- * @return
- */
- @Deprecated
- public String getMessage() {
- return description;
- }
-
- /**
- * @deprecated Use {@link #setDescription(String)} instead.
- * @param description
- */
- @Deprecated
- public void setMessage(String description) {
- this.description = description;
- }
-
- /**
- * Gets the description part of the notification message.
- *
- * @return The message description.
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * Sets the description part of the notification message.
- *
- * @param description
- */
- public void setDescription(String description) {
- this.description = description;
- }
-
- /**
- * Gets the position of the notification message.
- *
- * @return The position
- */
- public int getPosition() {
- return position;
- }
-
- /**
- * Sets the position of the notification message.
- *
- * @param position
- * The desired notification position
- */
- public void setPosition(int position) {
- this.position = position;
- }
-
- /**
- * Gets the icon part of the notification message.
- *
- * @return The message icon
- */
- public Resource getIcon() {
- return icon;
- }
-
- /**
- * Sets the icon part of the notification message.
- *
- * @param icon
- * The desired message icon
- */
- public void setIcon(Resource icon) {
- this.icon = icon;
- }
-
- /**
- * Gets the delay before the notification disappears.
- *
- * @return the delay in msec, -1 indicates the message has to be
- * clicked.
- */
- public int getDelayMsec() {
- return delayMsec;
- }
-
- /**
- * Sets the delay before the notification disappears.
- *
- * @param delayMsec
- * the desired delay in msec, -1 to require the user to click
- * the message
- */
- public void setDelayMsec(int delayMsec) {
- this.delayMsec = delayMsec;
- }
-
- /**
- * Sets the style name for the notification message.
- *
- * @param styleName
- * The desired style name.
- */
- public void setStyleName(String styleName) {
- this.styleName = styleName;
- }
-
- /**
- * Gets the style name for the notification message.
- *
- * @return
- */
- public String getStyleName() {
- return styleName;
- }
-
- /**
- * Sets whether html is allowed in the caption and description. If set
- * to true, the texts are passed to the browser as html and the
- * developer is responsible for ensuring no harmful html is used. If set
- * to false, the texts are passed to the browser as plain text.
- *
- * @param htmlContentAllowed
- * true if the texts are used as html, false if used as plain
- * text
- */
- public void setHtmlContentAllowed(boolean htmlContentAllowed) {
- this.htmlContentAllowed = htmlContentAllowed;
- }
-
- /**
- * Checks whether caption and description are interpreted as html or
- * plain text.
- *
- * @return true if the texts are used as html, false if used as plain
- * text
- * @see #setHtmlContentAllowed(boolean)
- */
- public boolean isHtmlContentAllowed() {
- return htmlContentAllowed;
- }
- }
-
- /**
- * Executes JavaScript in this window.
- *
- * <p>
- * This method allows one to inject javascript from the server to client. A
- * client implementation is not required to implement this functionality,
- * but currently all web-based clients do implement this.
- * </p>
- *
- * <p>
- * Executing javascript this way often leads to cross-browser compatibility
- * issues and regressions that are hard to resolve. Use of this method
- * should be avoided and instead it is recommended to create new widgets
- * with GWT. For more info on creating own, reusable client-side widgets in
- * Java, read the corresponding chapter in Book of Vaadin.
- * </p>
- *
- * @param script
- * JavaScript snippet that will be executed.
- */
- public void executeJavaScript(String script) {
-
- if (getParent() != null) {
- throw new UnsupportedOperationException(
- "Only application level windows can execute javascript.");
- }
-
- if (jsExecQueue == null) {
- jsExecQueue = new ArrayList<String>();
- }
-
- jsExecQueue.add(script);
-
- requestRepaint();
- }
-
- /**
* Returns the closable status of the sub window. If a sub window is
* closable it typically shows an X in the upper right corner. Clicking on
* the X sends a close event to the server. Setting closable to false will
@@ -2344,40 +889,13 @@ public class Window extends Panel implements URIHandler, ParameterHandler,
*/
@Override
public void focus() {
- if (getParent() != null) {
- /*
- * When focusing a sub-window it basically means it should be
- * brought to the front. Instead of just moving the keyboard focus
- * we focus the window and bring it top-most.
- */
- bringToFront();
- } else {
- super.focus();
- }
- }
-
- /**
- * Notifies the child components and subwindows that the window is attached
- * to the application.
- */
- @Override
- public void attach() {
- super.attach();
- for (Window w : subwindows) {
- w.attach();
- }
- }
-
- /**
- * Notifies the child components and subwindows that the window is detached
- * from the application.
- */
- @Override
- public void detach() {
- super.detach();
- for (Window w : subwindows) {
- w.detach();
- }
+ /*
+ * When focusing a sub-window it basically means it should be brought to
+ * the front. Instead of just moving the keyboard focus we focus the
+ * window and bring it top-most.
+ */
+ super.focus();
+ bringToFront();
}
/**